Linux service runtime

Linux uses Gunicorn 26's native asgi worker and foreground arbiter. The framework configures Gunicorn directly from .lclcfg; it does not invoke a second command-line parser or use the deprecated external Uvicorn worker. See the upstream native ASGI documentation.

lcl-fastapi serve -o config service.lclcfg

The current process becomes the Gunicorn master, whose PID and operating-system creation time are recorded before workers are forked. Application preload is disabled. Each worker loads its application and fresh configuration, then owns its Frame, logging, Snowflake generator, and FastAPI lifespan.

Startup failures stop the complete service with a nonzero exit status. Gunicorn 26's ASGI runner logs lifespan startup errors but normally returns success after its cleanup. The framework uses Gunicorn's documented worker_exit hook to translate the native lifespan manager's final _startup_failed flag into the arbiter's WORKER_BOOT_ERROR exit status. The original diagnostic and native cleanup are retained. This compatibility adapter does not replace the ASGI worker or change recovery after a successfully started worker crashes. The flag and exit ordering were checked against the upstream 26.0.0 sources and the exact 26.2.0 wheel used by CI. This adapter is coupled to that Gunicorn 26 interface; a missing flag is an incompatibility, not assumed startup success. The Linux real-process tests exercise this contract on the installed dependency.

Gunicorn receives the configured IPv4 bind address, port, worker count, backlog, keep-alive timeout, and graceful timeout. Native ASGI lifespan support is required; its event loop is asyncio. Duplicate Gunicorn access logging is disabled because the application emits request-correlated access records.

An authenticated shutdown response is sent before signaling the verified Gunicorn master with SIGTERM. Gunicorn performs its native graceful shutdown and worker joining. The CLI waits for that exact master identity to exit. Worker replacement does not alter the master listener settings.

The control-token file uses mode 0600. State and lease coordination use kernel file locks, which release if a process crashes. Keep the service state directory owned by and accessible only to the intended service account.

The shared real-process integration test runs on Linux in CI and verifies the Gunicorn master identity, worker replacement, token rejection, and lifecycle cleanup. Run the same test locally with:

venv/bin/python -m pytest tests/test_runtime_process.py

Use generated systemd and Nginx configuration as deployment input. Rendering does not install files, reload Nginx, or call systemctl. Review the generated configuration under your deployment policy.

See runtime ownership and observations for state consistency, configuration changes, deadlines, and predefined-route override consequences.

Development reload

Use serve -o config service.lclcfg -o hot_reload with server.reload_dirs: ["./src", "../shared"] to select recursive Python roots. Linux advances the shared watcher in the Gunicorn arbiter idle loop, then sends SIGTERM to the identity-verified worker. Gunicorn owns replacement. Hot reload forces one worker and warns when the configured count is higher. Native automatic reload is disabled. See the shared contract for errors, cleanup, and configuration boundaries.