# Buggy code
def process_alert(self, alert, hops=0):
    alert_type = str(type(alert)).split("'")[1].split(".")[-1]

    # Periodically, libtorrent will send us a state_update_alert, which contains the torrent status of
    # all torrents changed since the last time we received this alert.
    if alert_type == "state_update_alert":
        for status in alert.status:
            infohash = str(status.info_hash)
            if infohash not in self.torrents:
                self._logger.debug(
                    "Got state_update %s for unknown torrent %s", alert_type, infohash
                )
                continue
            self.torrents[infohash][0].update_lt_status(status)

    handle = getattr(alert, "handle", None)
    if handle and handle.is_valid():
        infohash = str(handle.info_hash())
        if infohash in self.torrents:
            self.torrents[infohash][0].process_alert(alert, alert_type)
        else:
            self._logger.debug("Got %s for unknown torrent %s", alert_type, infohash)

    if alert_type == "add_torrent_alert":
        infohash = str(handle.info_hash())
        if infohash in self.torrents:
            if alert.error.value():
                self.torrents[infohash][0].deferred_added.errback(alert.error.message())
                self._logger.debug("Failed to add torrent (%s)", alert.error.message())
            else:
                self.torrents[infohash][0].deferred_added.callback(handle)
                self._logger.debug("Added torrent %s", str(handle.info_hash()))
        else:
            self._logger.debug("Added alert for unknown torrent")

    elif alert_type == "torrent_removed_alert":
        infohash = str(alert.info_hash)
        if infohash in self.torrents:
            deferred = self.torrents[infohash][0].deferred_removed
            del self.torrents[infohash]
            deferred.callback(None)
            self._logger.debug("Removed torrent %s", infohash)
        else:
            self._logger.debug("Removed alert for unknown torrent")

    elif (
        alert_type == "peer_disconnected_alert"
        and self.tribler_session
        and self.tribler_session.lm.payout_manager
    ):
        self.tribler_session.lm.payout_manager.do_payout(alert.pid.to_string())

    elif alert_type == "session_stats_alert":
        queued_disk_jobs = alert.values["disk.queued_disk_jobs"]
        queued_write_bytes = alert.values["disk.queued_write_bytes"]
        num_write_jobs = alert.values["disk.num_write_jobs"]

        if queued_disk_jobs == queued_write_bytes == num_write_jobs == 0:
            self.lt_session_shutdown_ready[hops] = True

        if self.session_stats_callback:
            self.session_stats_callback(alert)

    if self.alert_callback:
        self.alert_callback(alert)


# Traceback (RuntimeError)
RuntimeError: [Failure instance: Traceback: <class 'twisted.internet.defer.AlreadyCalledError'>:
lib\site-packages\twisted\internet\base.py:1243:run
lib\site-packages\twisted\internet\base.py:1252:mainLoop
lib\site-packages\twisted\internet\base.py:878:runUntilCurrent
lib\site-packages\twisted\internet\task.py:239:__call__
--- <exception caught here> ---
lib\site-packages\twisted\internet\defer.py:150:maybeDeferred
Tribler\Core\Libtorrent\LibtorrentMgr.py:610:_task_process_alerts
Tribler\Core\Libtorrent\LibtorrentMgr.py:417:process_alert
lib\site-packages\twisted\internet\defer.py:459:callback
lib\site-packages\twisted\internet\defer.py:560:_startRunCallbacks
]

ERROR:Executor:********** TRIBLER CRASHED **********
ERROR:Executor:Tribler crashed after uptime of 2365.7650001 sec! Stack trace: Traceback (most recent call last):
File "TriblerGUI\event_request_manager.py", line 133, in on_read_data
RuntimeError: [Failure instance: Traceback: <class 'twisted.internet.defer.AlreadyCalledError'>:
lib\site-packages\twisted\internet\base.py:1243:run
lib\site-packages\twisted\internet\base.py:1252:mainLoop
lib\site-packages\twisted\internet\base.py:878:runUntilCurrent
lib\site-packages\twisted\internet\task.py:239:__call__
--- <exception caught here> ---
lib\site-packages\twisted\internet\defer.py:150:maybeDeferred
Tribler\Core\Libtorrent\LibtorrentMgr.py:610:_task_process_alerts
Tribler\Core\Libtorrent\LibtorrentMgr.py:417:process_alert
lib\site-packages\twisted\internet\defer.py:459:callback
lib\site-packages\twisted\internet\defer.py:560:_startRunCallbacks
]

INFO:Executor:About to shutdown Tribler

# Fixed code
def process_alert(self, alert, hops=0):
    alert_type = str(type(alert)).split("'")[1].split(".")[-1]

    # Periodically, libtorrent will send us a state_update_alert, which contains the torrent status of
    # all torrents changed since the last time we received this alert.
    if alert_type == "state_update_alert":
        for status in alert.status:
            infohash = str(status.info_hash)
            if infohash not in self.torrents:
                self._logger.debug(
                    "Got state_update %s for unknown torrent %s", alert_type, infohash
                )
                continue
            self.torrents[infohash][0].update_lt_status(status)

    handle = getattr(alert, "handle", None)
    if handle and handle.is_valid():
        infohash = str(handle.info_hash())
        if infohash in self.torrents:
            self.torrents[infohash][0].process_alert(alert, alert_type)
        else:
            self._logger.debug("Got %s for unknown torrent %s", alert_type, infohash)

    if alert_type == "add_torrent_alert":
        infohash = str(handle.info_hash())
        if (
            infohash in self.torrents
            and not self.torrents[infohash][0].deferred_added.called
        ):
            if alert.error.value():
                self.torrents[infohash][0].deferred_added.errback(alert.error.message())
                self._logger.debug("Failed to add torrent (%s)", alert.error.message())
            else:
                self.torrents[infohash][0].deferred_added.callback(handle)
                self._logger.debug("Added torrent %s", str(handle.info_hash()))
        else:
            self._logger.debug(
                "Added alert for unknown torrent or Deferred already called"
            )

    elif alert_type == "torrent_removed_alert":
        infohash = str(alert.info_hash)
        if infohash in self.torrents:
            deferred = self.torrents[infohash][0].deferred_removed
            del self.torrents[infohash]
            deferred.callback(None)
            self._logger.debug("Removed torrent %s", infohash)
        else:
            self._logger.debug("Removed alert for unknown torrent")

    elif (
        alert_type == "peer_disconnected_alert"
        and self.tribler_session
        and self.tribler_session.lm.payout_manager
    ):
        self.tribler_session.lm.payout_manager.do_payout(alert.pid.to_string())

    elif alert_type == "session_stats_alert":
        queued_disk_jobs = alert.values["disk.queued_disk_jobs"]
        queued_write_bytes = alert.values["disk.queued_write_bytes"]
        num_write_jobs = alert.values["disk.num_write_jobs"]

        if queued_disk_jobs == queued_write_bytes == num_write_jobs == 0:
            self.lt_session_shutdown_ready[hops] = True

        if self.session_stats_callback:
            self.session_stats_callback(alert)

    if self.alert_callback:
        self.alert_callback(alert)