Fix deadline consumer startup under granian RSGI

The mixin received the event loop from Kaya but ignored it, calling
asyncio.get_running_loop() instead. Under granian RSGI __rsgi_init__ runs
before the loop starts, so that raised RuntimeError and killed the
worker. Use the loop passed to setup(), falling back to the running loop
for the lazy calls from sync_deadline().
This commit is contained in:
2026-09-18 02:33:00 +00:00
parent 5b9e998739
commit c40ebd84d8
+10 -4
View File
@@ -214,13 +214,19 @@ async def _fire_hand_end(store: GameStore, state: GameState, entry: Dict[str, An
# --- consumer lifecycle -------------------------------------------------------
def ensure_consumer(store: GameStore) -> None:
"""Start the deadline consumer on the running loop if not yet running.
def ensure_consumer(
store: GameStore, loop: Optional[asyncio.AbstractEventLoop] = None
) -> None:
"""Start the deadline consumer on the given (or running) loop if not
yet running.
Called lazily whenever a deadline is enqueued (the ASGI test transport
never fires the lifespan hooks, so the mixin's ``setup`` alone is not
enough) and on application startup.
enough) and on application startup. The explicit ``loop`` matters at
startup: under RSGI granian calls ``setup`` before the loop runs, so
``asyncio.get_running_loop()`` would fail there.
"""
if loop is None:
loop = asyncio.get_running_loop()
for old in list(_consumers):
if old.is_closed():
@@ -284,7 +290,7 @@ class DeadlineSchedulerMixin(KayaMixin):
pass
def setup(self, loop: asyncio.AbstractEventLoop) -> None:
ensure_consumer(self._store)
ensure_consumer(self._store, loop)
def shutdown(self, loop: asyncio.AbstractEventLoop) -> None:
stop_consumer(loop)