erlang Cowboy/Ranch在客户端关闭连接时终止处理程序进程

l5tcr1uw  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(210)

我有一个Phoenix应用程序,HTTP端点后面有复杂的业务逻辑。此逻辑包括与数据库和一些外部服务的交互,一旦请求处理开始,就不能中断,直到所有操作都完成。
但如果客户端突然关闭连接,Cowboy或Ranch似乎会杀死请求处理程序进程(Phoenix控制器),这会导致业务流程部分执行。为了调试此问题,我在控制器操作中编写了以下代码:

Process.flag(:trap_exit, true)

receive do
  msg -> Logger.info("Message: #{inspect msg}")
after
  10_000 -> Logger.info("Timeout")
end

并为模拟连接关闭我设置超时:curl --request POST 'http://localhost:4003' --max-time 3。3秒后,在IEx控制台中,我看到进程即将退出:Message: {:EXIT, #PID<0.4196.0>, :shutdown} .
所以我需要让控制器完成它的工作,并回复客户端,如果它还在那里,或什么都不做,如果连接丢失。这将是实现这一点的最佳方式:

  • 在控制器操作中捕获退出并忽略退出消息;
  • 在控制器动作中产生未链接Task并等待其结果;
  • 以某种方式配置牛仔/牧场,使它不会杀死处理程序进程,如果可能的话(尝试了exit_on_close,但没有运气)?
cdmah0mi

cdmah0mi1#

处理进程将在请求结束后被终止,这是它们的目的。如果你想在后台处理一些数据,那么启动额外的进程。最简单的方法是你提出的第二种方法,但使用Task.Supervisor略有修改。
因此,在应用程序管理器中,您可以使用所选的名称启动Task.Supervisor

children = [
  {Task.Supervisor, name: MyApp.TaskSupervisor}
]

Supervisor.start_link(children, strategy: :one_for_one)

然后在请求处理程序中:

parent = self()
ref = make_ref()

Task.Supervisor.start_child(MyApp.TaskSupervisor, fn() ->
  send(parent, {ref, do_long_running_stuff()})
end)

receive do
  {^ref, result} -> notify_user(result)
end

这样您就不需要担心用户不再接收消息时处理情况

相关问题