等待 OTP 进程退出

s3c*_*ur3 5 elixir erlang-otp

假设您有一个 OTP 进程,您希望同步等待其完成(其中“完成”可能是正常退出或崩溃、停止等)。

\n

进一步假设,出于业务原因,您不能使用Task.async/1或相关Task实用程序生成此进程\xe2\x80\x94,它必须是不依赖于Task.await/2.

\n

有没有比简单地间歇性轮询更好的方法来做到这一点Process.alive?/1?我觉得这种事情可能有一个既定的模式,但我一生都找不到它。

\n
def await(pid, timeout) when timeout <= 0 do\n  if Process.alive?(pid) do\n    Process.exit(pid, :kill) # (or however you want to handle timeouts)\n  end\nend\n\n@await_sleep_ms 500\ndef await(pid, timeout) do\n  # Is there a better way to do this?\n  if Process.alive?(pid) do\n    :timer.sleep(@await_sleep_ms)\n    await(pid, subtract_timeout(timeout, @await_sleep_ms))\n  end\nend\n
Run Code Online (Sandbox Code Playgroud)\n

Vin*_*sil 4

Process.monitor/1函数从调用进程监视给定进程。将此与 结合起来receive,您可以对您的流程邮箱做出反应。

defmodule Await do
  def spawn do
    Kernel.spawn(fn -> :timer.sleep(2000) end)
  end
  
  def await_down(pid) do
    ref = Process.monitor(pid)
    receive do
      {:DOWN, ^ref, :process, ^pid, _reason} = message -> {:ok, message}
    after
      3000 -> {:error, :timeout}
    end
  end
end

pid = Await.spawn()
# => #PID<0.332.0>

Await.await_down(pid)
# => {:ok, {:DOWN, #Reference<0.4083290149.3661365255.180715>, :process, #PID<0.332.0>, :normal}}
Run Code Online (Sandbox Code Playgroud)

请注意接收块内的模式匹配,以确保消息不仅来自您的进程,而且来自特定的监视。