← Debugging Guides

阅读中文版本

Gunicorn — WORKER TIMEOUT and workers are killed

Diagnose Gunicorn worker timeouts by locating blocking request handlers and tuning timeout and worker class appropriately.

intermediatedebuggingpythongunicorn

Symptoms

  • [CRITICAL] WORKER TIMEOUT appears in the Gunicorn log
  • A request is killed and the client sees a 502 or 504
  • Workers are restarted repeatedly under load
  • The same request works locally but times out in production

Possible causes

  • A request handler blocks longer than the configured timeout without yielding
  • The worker class is synchronous while the code performs long I/O
  • An external dependency is slow or hangs and the handler waits unbounded
  • Too few workers cause requests to queue beyond the timeout

Diagnosis steps

Find the slow handler

grep -n "WORKER TIMEOUT" gunicorn.log | tail

Interpretation

The surrounding log lines and request path point at the handler or endpoint that exceeded the timeout.

Lower the timeout temporarily to reproduce deterministically

gunicorn app:app --timeout 10 --workers 2 --log-level debug

Interpretation

A short timeout makes slow handlers fail fast so you can identify them precisely.

Check worker class and concurrency

gunicorn app:app --worker-class gthread --threads 8

Interpretation

Switching to threaded workers shows whether the issue is blocking waits versus genuine long computation.

Root cause

A worker did not report back within the timeout because the handler was blocked, usually on synchronous I/O or on an unresponsive dependency, so Gunicorn killed and replaced the worker.

Fix

Reduce handler time by adding timeouts on outbound calls, offloading slow work to a background job, and choosing a worker class and count that match the workload.

Verify the fix

Re-run the workload and confirm no WORKER TIMEOUT entries, that response times stay under the timeout, and that workers are not restarted repeatedly.

Symptom walkthrough

Gunicorn logs [CRITICAL] WORKER TIMEOUT and kills a worker while a client waits, often returning 502 or 504. Workers may restart in a loop under load, and overall latency climbs because queued requests wait behind a blocked worker. The code may look fine locally where data volumes and network latency are lower.

Fix in practice

Make handlers finish within the timeout budget: set timeouts on database and HTTP calls, move heavy work to a queue, and avoid blocking calls in async handlers. Then choose a worker class and count suited to the workload rather than only raising the timeout, which merely delays the failure.

Verification

Rerun the load and confirm the WORKER TIMEOUT messages stop, response times stay below the limit, and workers are not being recycled repeatedly. Instrumenting handler duration helps confirm the fix rather than hiding it.

Diagnostic commands

Check the behavior with commands like these:

grep -n "WORKER TIMEOUT" gunicorn.log | tail
gunicorn app:app --timeout 10 --workers 2 --log-level debug
gunicorn app:app --worker-class gthread --threads 8