如何重新启动崩溃的受监督任务

How to restart a supervised task that crashes

{:ok, tas} = Task.Supervisor.start_link(restart: :transient, max_restarts: 4)
a = 1
Task.Supervisor.async_nolink(tas, fn -> IO.puts "#{a}..." end)
Task.Supervisor.async_nolink(tas, fn ->
  IO.puts "Not Restarting :( "
  1 = 2
end)
a =  a + 1
Task.Supervisor.async_nolink(tas, fn -> IO.puts "#{a}.." end)
a =  a + 1
Task.Supervisor.async_nolink(tas, fn -> IO.puts "#{a}.." end)

选项restart: :transient似乎没有任何作用。

我有几个任务 Task.async(fn(x) -> fetch_info(x) end 发出 http 请求以获取多个资源,并且出现超时错误。最好重试那些失败的任务,而不是使用 tryrescue

我认为 async_nolink 是我在没有使进程崩溃的情况下得到的最接近的结果。如果没有办法使用 Task,我们是否有更简单的方法使用 Supervisor 启动多个进程,一旦他们的工作完成就存在,如果他们失败就重新启动它们?

我认为 Tasks 不是您想要的最佳选择。在文档 Task Docs 中说:

This module defines a supervisor which can be used to dynamically supervise tasks. Behind the scenes, this module is implemented as a :simple_one_for_one supervisor where the workers are temporary (i.e. they are not restarted after they die).

:restart - the restart strategy, may be :temporary (the default), :transient or :permanent. Check Supervisor.Spec for more info. Defaults to temporary as most tasks can’t be effectively restarted after a crash;

您应该研究 GenServer 并建立一个工人池 GenServer Intro。 Little Elixir and OTP Guide 这本书在这方面很不错,我读了大约一半,它为 OTP、分发和主管提供了良好的基础。

编辑:我刚刚查看了这本书,找不到任何关于重新启动任务的信息,只有进程。

您只需使用 Task.Supervisor.start_child 而不是 Task.Supervisor.async_nolink 即可正确重新启动 children:

{:ok, tas} = Task.Supervisor.start_link(restart: :transient, max_restarts: 4)

Task.Supervisor.start_child(tas, fn -> 1 = 2 end)