Why am I getting "H12 Request timeout" Errors in Ruby?

Resolution

We generally see this pattern where one long-running action starts hogging the queue which in turn affects any subsequent requests.

Our router will drop a long-running request after 30 seconds, but the dyno behind it will continue processing the request until completion. Our router is unaware of it, though, so it'll dispatch new requests to that busy dyno. This effect tends to compound, and you'll experience requests queueing and eventually you will experience H12 errors even for unrelated URLs, such as static assets. H13 errors are similar in what causes them, but are primarily related to concurrent web servers.

You'll need to use a tool like New Relic, or another monitoring tool, to gain visibility into queueing in your app. If you use the latest New Relic gem you'll be able to see an accurate account of queueing in the New Relic graphs. Older versions of the gem inaccurately report queue time.

You'll also want to install something like the rack-timeout gem, which will ensure that a long running request is dropped at the dyno-level as well. This gem raises a Rack::TimeoutError exception when this happens.

With that in place, the compound effect is less likely to occur, but long-running actions still need to be addressed. Again, New Relic is a great tool to provide the visibility into your app to identify the long-running actions. You can then optimize them and make sure they're able to finish within a reasonable time, we suggest trying to keep all requests under 500ms. If they're performing any inherently long tasks, you should try to offload those to a background worker.

If you have a higher traffic production application we also suggest that you use the Puma web server, with multiple workers and threads. This will give you more concurrency, help cut back on queue time, and give you more overall performance out of each dyno.