Qwen Webhook Timeout After 30 Seconds in Docker Under CPU Limit
Problem
When the Qwen inference service runs inside a Docker container on a Linux host, HTTP requests sent to the /v1/completions webhook are terminated after exactly 30 seconds, even though the model can complete the inference in 45‑60 seconds under normal load. The client receives a 504 Gateway Timeout (or Docker’s client timeout) and the service logs show a generic “request timed out” message.
Typical symptom log excerpt:
2024-10-16T12:34:56.789Z ERROR webhook_handler.py:112 request_id=7f3c2a timeout after 30s
2024-10-16T12:34:56.790Z INFO docker: container qwen-infer exited with code 137
The failure is reproducible with any payload that requires more than 30 seconds of CPU time, but short prompts (< 10 seconds) succeed.
Root Cause
The container is started with a CPU quota that limits the process to 0.5 CPU cores (--cpus=0.5 or cpu_quota/cpu_period cgroup settings). Qwen’s transformer inference is CPU‑bound; when the quota is hit, the Linux scheduler throttles the process, causing the request handling thread to be blocked for the remainder of the 30‑second HTTP server timeout.
Docker’s default --stop-timeout and the webhook server’s own request timeout are both set to 30 seconds. Because the container never reaches the point where it writes a response, the HTTP server aborts the connection, and Docker reports a timeout.
Debug / Investigation Steps
-
Confirm CPU limits:
docker inspect qwen-infer --format='{{json .HostConfig.CpuQuota}} {{json .HostConfig.CpuPeriod}}'Typical output:
50000 100000This translates to 0.5 CPU.
-
Measure actual CPU throttling using cgroup stats:
cat /sys/fs/cgroup/cpu/docker/$(docker inspect -f '{{.Id}}' qwen-infer)/cpu.statSample output when the timeout occurs:
nr_periods 1200 nr_throttled 1185 throttled_time 11520000000High
nr_throttledindicates the process is being throttled for most of the time. -
Reproduce without CPU limit:
docker run -d --name qwen-unlimited \\ -p 8080:8080 \\ myrepo/qwen:latestRunning the same request now completes in ~55 seconds, confirming the limit is the culprit.
-
Check the webhook server timeout configuration (example for
uvicorn):cat /app/config.yaml | grep timeout # timeout: 30 -
Inspect host‑level Docker daemon timeout (unlikely but verify):
cat /etc/docker/daemon.json | grep -i timeout # {} (no custom timeout)
Solution
Two complementary changes resolve the issue:
1. Adjust container CPU allocation
Allocate at least one full CPU core to the inference container, or use a higher quota proportionate to the expected latency.
# Before
docker run -d --name qwen-infer \\
--cpus=0.5 \\
-p 8080:8080 \\
myrepo/qwen:latest
# After (allocate 2 CPUs)
docker run -d --name qwen-infer \\
--cpus=2 \\
-p 8080:8080 \\
myrepo/qwen:latest
Alternatively, remove the limit entirely if the host has spare capacity:
docker run -d --name qwen-infer -p 8080:8080 myrepo/qwen:latest
2. Increase the webhook request timeout
Modify the server configuration to allow longer processing times. For a FastAPI/Uvicorn deployment:
# config.yaml (before)
timeout: 30
# config.yaml (after)
timeout: 120 # generous buffer for heavy prompts
Restart the container after updating the config.
Why the fix works
- Providing sufficient CPU eliminates throttling, allowing the inference engine to progress without being paused by the scheduler.
- Extending the HTTP timeout gives the server enough wall‑clock time to finish the computation and send the response before the connection is closed.
Verification
After applying the changes, run a payload that previously timed out:
curl -X POST http://localhost:8080/v1/completions \\
-H "Content-Type: application/json" \\
-d '{"model":"qwen","prompt":"Explain quantum tunneling in detail."}'
Expected output (truncated):
{
"id":"cmpl-12345",
"object":"text_completion",
"created":1729104000,
"model":"qwen",
"choices":[{"text":"..."}],
"usage":{"prompt_tokens":12,"completion_tokens":210,"total_tokens":222}
}
Confirm no timeout logs appear:
2024-10-16T12:40:12.345Z INFO webhook_handler.py:98 request_id=7f3c2a completed in 52.3s
Also verify cgroup throttling stats have dropped:
cat /sys/fs/cgroup/cpu/docker/$(docker inspect -f '{{.Id}}' qwen-infer)/cpu.stat
nr_periods 1200
nr_throttled 0
throttled_time 0
Prevention / Best Practices
- Capacity planning: Benchmark the model on representative hardware and set
--cpusto at least the measured average CPU usage plus a safety margin (e.g., 1.5×). - Dynamic timeout: Expose a configurable timeout parameter and adjust per request size (e.g., longer for >512‑token prompts).
- Monitoring: Export
cpu.throttled.timeandcpu.throttled.periodsmetrics to Prometheus; alert when throttling exceeds 10 % over a 5‑minute window. - Graceful degradation: Implement request queueing or model off‑loading when CPU usage exceeds a threshold, returning a
429 Too Many Requestsinstead of a hard timeout. - Container health checks: Use a lightweight health endpoint that returns
200only when the process is not throttled (e.g., check/proc/self/statusforCpuQuota).
FAQ
- Why does the timeout happen exactly at 30 seconds?
Because the webhook server’stimeoutsetting defaults to 30 seconds and Docker’s default request timeout aligns with that value. When the process is throttled, it never reaches the response stage, so the server aborts at the configured limit. - Can I keep the CPU limit and still avoid timeouts?
Only if you also lower the model’s computational load (e.g., use a smaller quantized variant) or increase the timeout proportionally. However, the inference latency will still be bound by the limited CPU, so the practical solution is to raise the CPU allocation. - Is there a way to detect throttling from inside the container?
Yes. Read/sys/fs/cgroup/cpu/cpu.statand watchnr_throttledandthrottled_time. A non‑zero value indicates the scheduler is limiting CPU usage. - Do I need to adjust the host kernel’s CFS scheduler settings?
Usually not. Docker’s cgroup limits are sufficient. Changing host‑level scheduler parameters can have unintended side effects on other workloads. - What if the service must run on a shared node with strict CPU caps?
Consider deploying a separate inference node with dedicated resources, or use a GPU‑accelerated version of Qwen that is less CPU‑bound, thereby reducing the need for high CPU quotas.
Related Topic Hub: LLM Systems Troubleshooting Hub