Critical tasks now cause the app to exit, instead of letting it continue with broken functionality

This commit is contained in:
DevilXD committed 2024-07-16 18:16:31 +02:00
1 parent f32c8f25d8
commit 016955c8ba
3 files changed
+24 -7

No files matched your search

+5 -6
View File
@@ -849,7 +849,7 @@ class Twitch:
with suppress(asyncio.TimeoutError): with suppress(asyncio.TimeoutError):
await asyncio.wait_for(self._watching_restart.wait(), timeout=delay) await asyncio.wait_for(self._watching_restart.wait(), timeout=delay)
@task_wrapper @task_wrapper(critical=True)
async def _watch_loop(self) -> NoReturn: async def _watch_loop(self) -> NoReturn:
interval: float = WATCH_INTERVAL.total_seconds() interval: float = WATCH_INTERVAL.total_seconds()
while True: while True:
@@ -898,7 +898,7 @@ class Twitch:
logger.log(CALL, "No active drop could be determined") logger.log(CALL, "No active drop could be determined")
await self._watch_sleep(interval) await self._watch_sleep(interval)
@task_wrapper @task_wrapper(critical=True)
async def _maintenance_task(self) -> None: async def _maintenance_task(self) -> None:
claim_period = timedelta(minutes=30) claim_period = timedelta(minutes=30)
max_period = timedelta(hours=1) max_period = timedelta(hours=1)
@@ -911,10 +911,9 @@ class Twitch:
break break
next_trigger = min(now + claim_period, next_period) next_trigger = min(now + claim_period, next_period)
trigger_cleanup = False trigger_cleanup = False
while self._mnt_triggers and (switch_trigger := self._mnt_triggers[0]) <= next_trigger: while self._mnt_triggers and self._mnt_triggers[0] <= next_trigger:
next_trigger = self._mnt_triggers.popleft()
trigger_cleanup = True trigger_cleanup = True
self._mnt_triggers.popleft()
next_trigger = switch_trigger
if next_trigger == next_period: if next_trigger == next_period:
trigger_type: str = "Reload" trigger_type: str = "Reload"
elif trigger_cleanup: elif trigger_cleanup:
@@ -943,7 +942,7 @@ class Twitch:
await watching_channel.claim_bonus() await watching_channel.claim_bonus()
except Exception: except Exception:
pass # we intentionally silently skip anything else pass # we intentionally silently skip anything else
# this triggers this task restart every (up to) 60 minutes # this triggers a restart of this task every (up to) 60 minutes
logger.log(CALL, "Maintenance task requests a reload") logger.log(CALL, "Maintenance task requests a reload")
self.change_state(State.INVENTORY_FETCH) self.change_state(State.INVENTORY_FETCH)
+18
View File
@@ -131,6 +131,9 @@ def deduplicate(iterable: abc.Iterable[_T]) -> list[_T]:
def task_wrapper( def task_wrapper(
afunc: abc.Callable[_P, abc.Coroutine[Any, Any, _T]] | None = None, *, critical: bool = False
):
def decorator(
afunc: abc.Callable[_P, abc.Coroutine[Any, Any, _T]] afunc: abc.Callable[_P, abc.Coroutine[Any, Any, _T]]
) -> abc.Callable[_P, abc.Coroutine[Any, Any, _T]]: ) -> abc.Callable[_P, abc.Coroutine[Any, Any, _T]]:
@wraps(afunc) @wraps(afunc)
@@ -141,8 +144,23 @@ def task_wrapper(
pass pass
except Exception: except Exception:
logger.exception(f"Exception in {afunc.__name__} task") logger.exception(f"Exception in {afunc.__name__} task")
if critical:
# critical task's death should trigger a termination.
# there isn't an easy and sure way to obtain the Twitch instance here,
# but we can improvise finding it
from twitch import Twitch # cyclic import
probe = args and args[0] or None # extract from 'self' arg
if isinstance(probe, Twitch):
probe.close()
elif probe is not None:
probe = getattr(probe, "_twitch", None) # extract from '_twitch' attr
if isinstance(probe, Twitch):
probe.close()
raise # raise up to the wrapping task raise # raise up to the wrapping task
return wrapper return wrapper
if afunc is None:
return decorator
return decorator(afunc)
def invalidate_cache(instance, *attrnames): def invalidate_cache(instance, *attrnames):
+1 -1
View File
@@ -141,7 +141,7 @@ class Websocket:
) )
break break
@task_wrapper @task_wrapper(critical=True)
async def _handle(self): async def _handle(self):
# ensure we're logged in before connecting # ensure we're logged in before connecting
self.set_status(_("gui", "websocket", "initializing")) self.set_status(_("gui", "websocket", "initializing"))