Back to Blog
Python

Configuring Python Gunicorn Workers, Timeout, and Logging

python gunicorn workers timeout and logging: Learn how to configure Gunicorn worker count, timeout, and logging for Python web apps, including access and error logs fo...

gunicornpythontimeoutloggingweb-serverworkers
Diagram of Gunicorn worker processes with a clock for timeout and log files for logging.

When running a Python web application under Gunicorn, the worker count, timeout, and logging settings determine how well the server handles traffic and how quickly you can diagnose failures. These three settings are often configured together because they interact: a worker that takes too long triggers the timeout, and the logging output tells you why. This article explains how to configure python gunicorn workers timeout and logging in a production environment.

Why Worker Count, Timeout, and Logging Are Linked

Gunicorn uses a master process that spawns several worker processes to handle incoming requests. Each worker processes requests according to the worker type you choose. The --workers option controls how many of these processes exist. The --timeout option defines how long a worker is allowed to spend on a single request before the master kills it. Logging records both the normal request flow and the errors that occur when a worker fails or times out.

These settings are not independent. A low timeout can kill workers that are legitimately slow, while a high timeout can let a stuck worker consume resources for too long. Logs are the only way to see which requests are slow and whether timeouts are happening. Without proper logging, you are guessing at the cause of intermittent 502 errors or dropped connections.

Setting the Number of Workers

The number of workers is set with the --workers command-line option or the workers key in a Gunicorn configuration file. For synchronous workers, a common starting point is 2 * CPU cores + 1, but that is a rule of thumb, not a strict formula. The actual number depends on your application's concurrency model, the worker type, and the available memory.

gunicorn --workers 4 myapp:app

If your application uses async workers, such as gevent or uvicorn workers, you can often use fewer workers because each worker can handle many requests concurrently. For sync workers, each worker processes one request at a time, so you need more workers to handle concurrent traffic. Too many workers can exhaust memory, especially if each worker loads a large application into memory. Monitor your process memory and adjust the count accordingly.

Configuring the Timeout

The --timeout option sets the number of seconds Gunicorn waits for a worker to finish handling a request before killing it. The default is 30 seconds. This is not a request timeout in the usual sense; it is a worker-level timeout. If a worker does not send a response within the timeout period, the master process terminates that worker and starts a replacement.

gunicorn --timeout 60 myapp:app

A common mistake is to treat this as a client request timeout. The timeout applies to the time a worker spends on a request, including time spent waiting for upstream services, database queries, or file I/O. If your application legitimately needs more than 30 seconds for some requests, you must increase the timeout or restructure the work to run outside the request cycle. Long-running tasks are better handled by a background job queue than by holding a worker.

What Happens When a Worker Times Out

When a worker exceeds the timeout, Gunicorn's master process kills it. The in-flight request is dropped, and the client typically receives a connection reset or a 502 Bad Gateway if a reverse proxy is in front. The master then spawns a new worker to replace the killed one. This behavior prevents a single stuck worker from blocking the entire server.

The timeout is also a safety net for code that hangs due to a deadlock, an infinite loop, or a blocked network call. Without a timeout, such a worker would consume a slot forever. However, a timeout that is too low can kill workers during normal traffic spikes or when the application is slow due to a downstream dependency. The error log will contain a message about the worker timing out, which is the first clue for debugging.

Configuring Logging in Gunicorn

Gunicorn provides two log streams: the error log and the access log. The error log records Gunicorn's own messages, including worker startup, worker shutdown, and timeout events. The access log records each HTTP request with details like the client IP, request method, path, status code, and response time.

You configure both with command-line options:

gunicorn --error-logfile - --access-logfile - --log-level info myapp:app

Here, - sends the logs to stdout. In production, you will typically write to files:

gunicorn --error-logfile /var/log/gunicorn/error.log --access-logfile /var/log/gunicorn/access.log --log-level warning myapp:app

The --log-level option controls the verbosity of the error log. info includes worker lifecycle messages, while warning only shows warnings and errors. For debugging timeout issues, info is useful because it shows when workers are started and killed.

Logging Request Details with Access Logs

Access logs are essential for understanding which requests are slow or failing. By default, Gunicorn logs a standard format that includes the client IP, request line, status, and response length. You can customize the format with --access-logformat to include response time, which is critical for diagnosing timeouts.

gunicorn --access-logfile - --access-logformat '%(h)s %(t)s "%(r)s" %(s)s %(b)s %(L)s' myapp:app

The %(L)s field is the request time in seconds. Adding this to your access log lets you see which endpoints take the longest. Note that the access log is written after the response is sent. If a worker times out before completing the request, the access log may not contain an entry for that request, because the worker was killed before it could log. In that case, the error log is the only record of the timeout.

Using Logs to Diagnose Timeout Issues

When you see a spike in 502 errors or dropped connections, the first step is to check the error log for timeout messages. The error log will show which worker was killed and at what time. Then, look at the access log around that time to see if any requests were slow or incomplete. If a request appears in the access log with a very long response time, it is likely the cause of the timeout.

You can also add application-level logging to track request duration and identify slow code paths. For example, a Python logging middleware can log the time taken for each request. This gives you a more detailed view than Gunicorn's access log alone. Combining Gunicorn's logs with application logs gives you a complete picture of where time is spent.

Production Considerations for Worker and Timeout Settings

Choosing the right worker count and timeout requires measuring your application's actual behavior. Start with a reasonable worker count based on your CPU and memory, then monitor response times and error rates. If you see frequent timeouts, check whether the requests are genuinely slow or whether the worker count is too low to handle the traffic. Increasing the timeout may mask a performance problem that should be fixed in the code.

For long-running requests, consider using async workers or moving the work to a background queue. A sync worker that holds a request for 60 seconds is unavailable for other requests, so a small number of slow requests can exhaust the worker pool. Async workers handle concurrency differently and may be a better fit for I/O-bound workloads.

Log rotation is another operational concern. Access logs can grow quickly under high traffic. Configure log rotation at the system level to prevent disk exhaustion. Gunicorn itself does not rotate logs, so you need an external tool like logrotate to manage file sizes.

Finally, remember that Gunicorn's timeout is not a substitute for a proper client-side timeout. A reverse proxy like Nginx should have its own timeout settings to avoid waiting indefinitely for Gunicorn to respond. Set the proxy timeout slightly higher than Gunicorn's timeout so the proxy can return a clean error to the client instead of a hung connection.

python gunicorn workers timeout and logging: Practical Usage | RYUSLOG DEV