等待 OTP 进程退出

Posted

技术标签:

【中文标题】等待 OTP 进程退出【英文标题】:Await an OTP process to exit 【发布时间】:2021-09-24 13:54:38 【问题描述】:

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

进一步假设出于业务原因,您不能使用 Task.async/1 或相关的 Task 实用程序生成此进程 - 它必须是不依赖于 Task.await/2 的“正常”进程。

除了间歇性地轮询Process.alive?/1,还有更好的方法吗?这让我印象深刻,因为它可能有一个既定的模式,但对于我的生活,我找不到它。

def await(pid, timeout) when timeout <= 0 do
  if Process.alive?(pid) do
    Process.exit(pid, :kill) # (or however you want to handle timeouts)
  end
end

@await_sleep_ms 500
def await(pid, timeout) do
  # Is there a better way to do this?
  if Process.alive?(pid) do
    :timer.sleep(@await_sleep_ms)
    await(pid, subtract_timeout(timeout, @await_sleep_ms))
  end
end

【问题讨论】:

你知道进程是否正在捕获退出吗?在任何情况下,Process.monitor/1receive/1 在消息处理程序中使用 timeout: :infinity 和模式匹配 PID 是一种可行的方法。 啊哈! Process.monitor/1 正是我想要的! 【参考方案1】:

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

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

【讨论】:

【参考方案2】:

看起来Process.monitor/1 可能就是您要找的东西?文档中的示例:

pid = spawn(fn -> 1 + 2 end)
#=> #PID<0.118.0>
Process.monitor(pid)
#=> #Reference<0.906660723.3006791681.40191>
Process.exit(pid, :kill)
#=> true
receive do
  msg -> msg
end
#=> :DOWN, #Reference<0.906660723.3006791681.40191>, :process, #PID<0.118.0>, :noproc

【讨论】:

以上是关于等待 OTP 进程退出的主要内容,如果未能解决你的问题,请参考以下文章

Linux——进程等待程序替换

Linux——进程等待程序替换

非阻塞等待子进程退出

在退出进程时等待线程完成

shell等待特定进程pid退出的方法

shell等待特定进程pid退出的方法