Answer to the Questions
1. Is there a supported way to request a per‑route timeout override from the Heroku router?
• No. The router’s 30‑second limit is hard‑coded and cannot be changed through config, add‑ons, or tier upgrades.
2. Can application‑level keep‑alive packets or HTTP 100 Continue reset the router’s timer?
• No. The router starts its countdown as soon as the request arrives and only stops it when the first byte of a response is sent. Keep‑alive heartbeats or 100 Continue do not affect this timer.
3. Does any Heroku add‑on or experimental feature provide a configurable request timeout for HTTP traffic?
• None. Heroku’s documentation lists no add‑on that exposes a longer request timeout for HTTP routes.
Confirmed Facts
- The Heroku Router enforces a strict 30‑second timeout for all inbound HTTP requests.
- If the application does not send any response within 30 s, the router terminates the connection and returns an
H12 - Request Timeout error.
- HTTP 100 Continue and keep‑alive packets do not reset the router’s timer.
- WebSocket connections have a different timeout model, but they are not a direct replacement for long‑running REST endpoints.
Why HTTP Tricks Don’t Work
The router’s timeout logic is implemented at the load‑balancer layer, independent of the application’s TCP socket state. It does not observe application‑level keep‑alive or streaming events. Consequently, any attempt to “trick” the router by sending periodic data will still hit the 30‑second boundary unless the first byte of a final response arrives.
Recommended Architecture for Long‑Running Endpoints
- Return Early – When a client hits a long‑running endpoint, immediately respond with
202 Accepted and a JSON payload containing a task_id or a status URL.
- Background Worker – Off‑load the heavy processing to a worker dyno (e.g., Sidekiq, Celery, or a custom Go worker) that reads the task from a queue (Redis, RQ, etc.).
- Persist Status – Store the task’s progress and result in a shared data store (Redis, Postgres, S3) so the web dyno can report status without re‑executing.
- Client Polling or Webhook – The client polls the status endpoint until the result is ready, or the server pushes a webhook/callback once the worker completes.
- Optional Streaming – If you need to stream incremental data, consider WebSocket or Server‑Sent Events (SSE) which are not subject to the 30‑second HTTP timeout.
Practical Verification Steps
# Verify the H12 trigger
curl -w "%{http_code}" -o /dev/null -s http://yourapp.herokuapp.com/long_running_endpoint
# Expect 504 or 502 with H12 message after 30s
# Implement 202 Accepted pattern
# Example (Node.js/Express)
app.post('/process', async (req, res) => {
const id = uuidv4();
await enqueueTask(id, req.body);
res.status(202).json({ task_id: id, status_url: `/tasks/${id}` });
});
Missing Diagnostic Detail (Optional)
To fine‑tune the worker side, it helps to know whether the long‑running operation is idempotent and how often it can be safely retried. If you can share that, we can suggest a more precise retry strategy.