backend1 min read
Recycling Gunicorn Workers to Contain ASGI Memory Growth
Long-lived ASGI workloads can be difficult to keep within a small server's memory budget. Rising process memory or an OOM kill is evidence of memory pressure, but it does not by itself tell us whether the application is leaking memory, the allocator is retaining it, or the workload needs more memory.
A single Daphne process serving streaming responses can retain a large amount of memory. That observation would not establish that Daphne itself caused fragmentation. This note does not include profiling evidence that separates server behavior from application allocations.
Recycling workers
One way to contain memory retained by long-running processes is to run the ASGI application under Gunicorn with Uvicorn workers and recycle them after a set number of requests:
gunicorn core.asgi:application -k uvicorn.workers.UvicornWorker --workers 4 --max-requests 1000 --max-requests-jitter 50
Worker exit allows the OS to reclaim that process's memory. The jitter spreads out restarts. This is a containment measure, not proof that the underlying cause has been fixed. It also does not cap the memory a worker can use during a long request.
The worker class in this example is version-dependent. Check the Uvicorn and Gunicorn versions before adopting the command, and choose a worker count that fits the available RAM. More workers can increase total memory use.
Limiting the container
A Docker memory limit, such as mem_limit: 1G, puts another bound on the workload. Exceeding it can trigger an OOM kill within the container. A restart depends on the container's restart policy and which process exits; the limit does not guarantee that Docker will restart the whole container.
Both recycling and limits can interrupt requests. They are ways to bound the impact while investigating memory growth, not evidence that Gunicorn is inherently more reliable than Daphne or that the rest of the host cannot run out of memory.