Настроить время ожидания запроса в Фениксе?

Я хочу, чтобы запросы истекали через некоторое время, скажем, 20 секунд. Если для отправки ответа приложению требуется более 20 секунд, Phoenix должен отменить выполнение и немедленно ответить с некоторой ошибкой (предпочтительно HTTP 503).

Я просмотрел документы по Фениксу, но не нашел упоминаний о параметре тайм-аута запроса. Похоже, у Ковбоя есть :timeout параметр, который я попытался установить на 10 мс, но он все еще позволил запросу занять 8951 мс:

config :app, SomeApp.Endpoint,
  http: [port: 4000, timeout: 10]

Оказывается, документы Cowboy определяют эту опцию как:

Время в мс без запросов перед тем, как Cowboy закроет соединение.

это не то, что я ищу.

Можно ли установить тайм-аут запроса в Фениксе?

1 ответ

Решение

Это ни в коем случае не является обязанностью веб-сервера / фреймворка. Ковбой понятия не имеет (и не должен знать!) О том, что происходит в приложении, он обслуживает соединения. Феникс может позаботиться об этом, но это нарушит SRP. В конце концов, вышеупомянутый тайм-аут больше относится к бизнес-логике. Представьте, что ковбой / феникс будет пытаться справиться с таймаутом: что должно произойти с выполняемым в настоящее время обработчиком?

Тем не менее, приложение должно обрабатывать такие тайм-ауты, и это относительно просто: нужно просто обернуть базовое выполнение в задачу желаемым таймаутом. Таким образом, он будет гибким, надежным, и вы можете указать, какие контроллеры / действия должны вести себя таким образом, а какие - нет.

В псевдокоде (это реальный код, но я его не тестировал):

def create(conn, params) do # or any other action
  fn -> prepare_result end
  |> Task.async()
  |> Task.yield(10)  # ⇐ HERE!!!
  |> case do
    {:ok, result} -> # success
      conn
      |> put_status(200)
      |> json(%{ok: result})
    nil -> # not finished yet; do smth with the task itself!
      conn
      |> put_status(503)
      |> json(%{error: :timeout})
    {:exit, reason} -> # should not happen [see Task.yield/2 docs]
      conn
      |> put_status(500) # internal server error; unexpected
      |> json(%{error: reason})
  end
end

Task.yield/2,


Sidenote: конечно, если вам нужно такое поведение во всем приложении, просто объявите макрос, делающий это или что-то подобное.

Если это..

config :app, SomeApp.Endpoint,
  http: [port: 4000, timeout: 10]

не работает.. Попробуйте изменить на..

config :app, SomeApp.Endpoint,
  http: [port: 4000, protocol_options: [idle_timeout: 10_000]]

Другие вопросы по тегам