Lifecycle and shutdown
Status: Draft; implementation checked against the development source on 2026-09-08.
Application on_startup hooks run in registration order; on_shutdown hooks
run in reverse. Either hook may be synchronous or asynchronous. Synchronous
hooks run directly on the event-loop thread, so keep them short or explicitly
offload blocking work. Ordinary hook exceptions are logged and the sequence
continues. Raise genro_asgi.lifespan.FatalBootError from startup when a missing
prerequisite must prevent the server from starting.
from genro_asgi import RoutedApplication
from genro_asgi.lifespan import FatalBootError
class Catalog(RoutedApplication):
async def on_startup(self):
if self.config("parameters.catalog_url", default=None) is None:
raise FatalBootError("Configure parameters.catalog_url")
async def on_shutdown(self):
pass # close application-owned resources here
This is a hook fragment, not a running catalog service. Supply its configuration and routes before serving it.
Admission and draining
The server begins with state RUNNING. Lifespan shutdown changes it to
shutdown_mode (normally STOPPING; the reload child uses QUITTING) before
waiting for in-flight registered requests, then runs the application hooks.
The registry drain has its own finite timeout. Requests reaching core HTTP
dispatch while not running receive 503 with Retry-After and are not registered.
Middleware that answers on its own can still answer before that gate.
New WebSocket handshakes are refused before accept whenever the server is not running, including raw WebSockets. A browser sees a failed handshake rather than a readable post-accept close code. See WebSockets.
shutdown_timeout_seconds defaults to 5.0 and controls uvicorn’s wait for
open connections before cancelling them, allowing lifespan shutdown to run even
when an HTTP stream never ends:
from genro_asgi.config import AsgiConfigBuilder
class Configuration(AsgiConfigBuilder):
def main(self, root):
root.configuration().server(shutdown_timeout_seconds=5.0)
The same value can be passed to AsgiServer(shutdown_timeout_seconds=5.0).
This is a connection-drain timeout, not a five-second deadline for the entire
process: application hooks and worker shutdown have their own work to finish.
Stop a foreground server with Ctrl-C; the CLI’s stop sends SIGTERM to the
named server (or reload supervisor). See CLI.