diff --git a/packages/kaya-core/src/kaya/core/_mixin.py b/packages/kaya-core/src/kaya/core/_mixin.py index fd9444b..f743939 100644 --- a/packages/kaya-core/src/kaya/core/_mixin.py +++ b/packages/kaya-core/src/kaya/core/_mixin.py @@ -29,9 +29,22 @@ class KayaMixin(ABC): pass def setup(self, loop: AbstractEventLoop) -> None: - """Called on lifespan startup (default: no-op).""" + """Called on lifespan startup (default: no-op). + + Under RSGI (granian) the loop is NOT yet running when this is + called: schedule work on the passed ``loop`` (e.g. + ``loop.create_task``) instead of calling + ``asyncio.get_running_loop()``, which raises ``RuntimeError`` + there. Under ASGI the lifespan runs inside a coroutine, so a + running loop happens to be available — do not rely on that. + """ pass def shutdown(self, loop: AbstractEventLoop) -> None: - """Called on lifespan shutdown (default: no-op).""" + """Called on lifespan shutdown (default: no-op). + + As with :meth:`setup`, use the passed ``loop``; it may already be + stopped under RSGI, so ``asyncio.get_running_loop()`` is not + reliable here either. + """ pass