【问题标题】:handle_info :DOWN is not called after monitored process dieshandle_info :DOWN 在被监控进程死亡后不被调用
【发布时间】:2018-11-15 19:59:08
【问题描述】:

我遇到了Process.monitor/1 的问题。我最初的用例是监控 Phoenix Channel 并在它死后进行一些清理。但是,我没有设法在 Phoenix 中设置它,并决定使用纯 GenServer 对其进行测试。

所以,我有一个简单的GenServer,我想跟踪它何时死亡:

defmodule Temp.Server do
  use GenServer

  def start_link(_), do: GenServer.start_link(__MODULE__, %{})

  def init(args) do
    Temp.Monitor.monitor(self())
    {:ok, args}
  end
end

还有另一个监控的 GenServer:

defmodule Temp.Monitor do
  use GenServer
  require Logger

  def start_link(_) do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  def monitor(pid) do
    Process.monitor(pid)
  end

  def handle_info({:DOWN, ref, :process, _, _}, state) do
    Logger.info("DOWN")

    {:noreply, state}
  end
end

所以,如果我理解正确,Process.monitor 将开始监视Temp.Server 进程,并在Server 进程终止时调用匹配:DOWNhandle_info。如果我在iex 试试:

iex> {_, pid} = Temp.Server.start_link([])
{:ok, #PID<0.23068.3>}                    
iex> Process.exit(pid, :kill)             
true     

我希望从Monitor 模块调用handle_info 并记录“DOWN”,但这不会发生。我究竟做错了什么?我认为它不起作用,因为我从服务器进程 Temp.Monitor.monitor(self()) 调用监视,但我只是不知道我应该怎么做。

【问题讨论】:

    标签: process elixir monitor


    【解决方案1】:

    当您调用Temp.Monitor.monitor/1 方法时,它仍然在Temp.Server 自己的进程中运行,而不是Temp.Monitor 的。这意味着当Temp.Server 死亡时,:DOWN 消息会发送到Temp.Server,这是多余的。

    您要做的是,将您的服务器进程的pid 传递给Temp.Monitor 并让它从它自己的进程中调用Process.Monitor 方法,以便它可以监控它。这只能从GenServer callbacks 之一发生。

    您可以通过将实施移至 handle_call/3handle_cast/3 来做到这一点:

    defmodule Temp.Monitor do
      use GenServer
      require Logger
    
      def start_link(_) do
        GenServer.start_link(__MODULE__, [], name: __MODULE__)
      end
    
      def monitor(pid) do
        GenServer.cast(__MODULE__, {:monitor, pid})
      end
    
      def handle_cast({:monitor, pid}, state) do
        Process.monitor(pid)
        {:noreply, state}
      end
    
      def handle_info({:DOWN, ref, :process, _, _}, state) do
        Logger.info("DOWN")
    
        {:noreply, state}
      end
    end
    

    【讨论】:

    • 成功了。谢谢。现在我明白了一点。我不认为我在 GenServer 中定义的 API 函数和回调会在不同的进程中运行(我想我很困惑,因为它们在同一个模块中,所以我认为它们共享相同的进程或 smth)。
    • 如果我想同时使用terminate 回调和handle_info :DOWN 怎么办。是否保证在终止回调之后总是最后调用后者?
    • 我不确定顺序,但无论如何你应该保持它们的逻辑解耦。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-16
    • 1970-01-01
    相关资源
    最近更新 更多