我遇到Process.monitor/1
的问题。我最初的用例是监视Phoenix Channel并在其死后进行一些清理。但是,我没有设法在Phoenix上进行设置,而是决定使用纯GenServers对其进行测试。
所以,我有一个简单的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
进程,并在handle_info
进程终止时调用与:DOWN
相匹配的Server
。如果我在iex
中尝试过:
iex> {_, pid} = Temp.Server.start_link([])
{:ok, #PID<0.23068.3>}
iex> Process.exit(pid, :kill)
true
我希望从handle_info
模块调用Monitor
并记录“ DOWN”,但是不会发生。我究竟做错了什么?我认为这是行不通的,因为我从服务器进程Temp.Monitor.monitor(self())
进行监视,但我只是想不出该怎么做。
答案 0 :(得分:1)
调用Temp.Monitor.monitor/1
方法时,它仍在Temp.Server
自己的进程中运行,而不是Temp.Monitor
的进程中运行。这意味着:DOWN
死亡时,Temp.Server
消息会发送到Temp.Server
,这是多余的。
您要做的是将服务器进程的pid
传递到Temp.Monitor
,并使其从自己的进程中调用Process.Monitor
方法,以便它可以对其进行监视。这只能从GenServer callbacks之一发生。
您可以通过将实现移至handle_call/3
或handle_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