How to proper do request timeouts with Phoenix?


I’m comming from a Go background and this kind of thing in Go is trivial, but i’m struggling to do the same with Phoenix. I want a middleware that for each request it track the time of execution, if its greater then a given value (1s per example) it should render immediately a json with a timeout message and stop the underneath processing.

It’s easy track the timeout and render the message to the client, the problem is i’m doing double writes at the connection:

[info] GET /resources
[debug] Processing with Flare.Resource.Handler.index/2
  Parameters: %{}
  Pipelines: [:api]
[info] Sent 408 in 501ms
[debug] QUERY OK source="resources" db=0.8ms decode=0.1ms queue=0.1ms
SELECT r0."id", r0."addresses", r0."path", r0."change", r0."inserted_at", r0."updated_at" FROM "resources" AS r0 []
[info] Sent 200 in 1003ms

The timeout middleware wait 500ms and the controller has a 1s sleep. How can i prevent the controller from writing if the middleware already writed?


Without knowing how you implemented what part of your timeout stuff, we can’t help you.

Can you perhaps create an example app which shows your problem?

Anyway, I do not think it is a good think to cancel half finished requests from the server side. If done wrong the state could end up inconsistent.

Creating rollback machanisms might be much harder than the actual timeout.

Simply processing the request from start to finish and handle timeouts at the clientside should be the way to go in my opinion.


Its a client requirement, the endpoint should have a fixed timeout, so, after a period of time, even if the request don’t complete because a server overload or database slowdown, a answer should be sent to the client informing the timeout.

As i’m not yet familiar with Elixir/Plug architecture, the double write was a side effect of a bad programmed Plug. I deleted the code, but was something like this:

defmodule Timeout do
  import Plug.Conn
  def init(options) do

  def call(conn, _opts) do
    Task.async(fn -> 
      |> put_resp_content_type("text/plain")
      |> send_resp(408, "timeout")


I know the plug is wrong, the connection is already released when the task executes. I’m gonna talk with the client to see if this can be done client side.

But i’m with this tech doubt now. This can be done without changing too much the code? Like before each render check any global struct to see if the request is already timeout. Or any kind of callback to ignore the content writed on a connection?

Tried to use the register_before_send, but no success too. Can’t override the connection write.


The important question is if only a response should be sent or if the triggered work should get canceled as well. Also you might want to look into the Task module and OTP, because you could just offload the hard work into another process and leave your request livecycle to only care about handing the timeout requirement.


Shall this happen everywhere or only at certain places?

If at certain places is enough, you could just use a Task for the hardwork and use Task.yield/2 to wait for the result.

Roughly like this:

t = Task.async(&do_hardworkd/0)
case Task.yield(t, 1000) do # timeout of a second
  {:ok, result} -> handle_result(result)
  nil -> handle_timeout()
  {:exit, reason} -> handle_error(reason)


Everywhere, it’s a middleware that should stay at the pipeline to executes in all requests. But i don’t think this is possible, seems a plug limitation, after the conn is returned from the function, we loose 100% the control of it, the only way is to instrument everywhere the connections is used to check if first it’s already writed.

But, nevermind, we gonna handle this at client side, was just curious about how to do.


Doesn’t seem too hard to do, but if requests take long then ‘those’ areas should probably have timeouts, not the conn itself (and most timeouts do exist in the system and default to 5s).

However, to do it at the plug layer I’d make a plug that creates messages a timing process it’s own pid and how long, then that other process would wait then kill that pid after the time is elapsed. Should also have an after_plug or whatever it was called function registered to send a cancel message too, just to clean things up a bit faster.


One question, it’s possible to use defdelegate to override the render inside controllers? If this is possible, i could create a module that receive the renders, check in a agent if the connection already writed or got a timeout and write the proper response to the client.

Tried sometimes, but didn’t worked.