Heroku

How It Works

Request Timeout

Last Updated: 14 February 2012

background routing timeout worker

Table of Contents

Additional concurrency is of no help whatsoever if you are encountering request timeouts. You can crank your dynos to the maximum and you’ll still get a request timeout, since it is a single request that is failing to serve in the correct amount of time. Extra dynos increase your concurrency, not the speed of your requests.

The Heroku routing mesh detects and terminates requests taking more than 30 seconds to respond. An error page is served to the client and an error is emitted to your application logs.

Web requests should be typically processed in no more than 500ms, and ideally under 200ms. So a request which runs 30 seconds is two orders of magnitude slower than a best-practice response!

Long-polling and streaming responses

Cedar supports HTTP 1.1 features such as long-polling and streaming responses. An application has an initial 30 second window to respond with a single byte back to the client. However, each byte transmitted thereafter (either received from the client or sent by your application) resets a rolling 55 second window. If no data is sent during the 55 second window, the connection will be terminated.

Timeout behavior

Even though an error page will be issued to the client, and the connection terminated, when a timeout occurs the dyno is still left to process the request. Subsequent requests may then be routed to the same dyno which will be unable to respond (depending on the concurrency behavior of the application’s language/framework) causing further degradation.

If a concern, app-level tools such as Ruby’s rack-timeout should be used to ensure dynos don’t remain tied up after 30 seconds of inactivity.

Debugging request timeouts

One cause of request timeouts is an infinite loop in the code. Test locally (perhaps with a copy of the production database pulled down with pgbackups) and see if you can replicate the problem and fix the bug.

Another possibility is that you are trying to do some sort of long-running task inside your web request, such as:

  • Sending an email
  • Accessing a remote API (posting to Twitter, querying Flickr, etc.)
  • Web scraping / crawling
  • Rendering an image or PDF
  • Heavy computation (computing a fibonacci sequence, etc.)
  • Heavy database usage (slow or numerous queries, N+1 queries)

If so, you should move this heavy lifting into a background job which can run asynchronously from your web request. See Queueing for details.

Another class of timeouts occur when an external service used by your application is unavailable or overloaded. In this case, your web app is highly likely to timeout unless you move the work to the background. In some cases where you must process these requests during your web request, you should always plan for the failure case. Most languages let you specify a timeout on HTTP requests, for example.