handle_info :DOWN 在被监控的进程结束后不被调用
handle_info :DOWN is not called after monitored process dies
我遇到了 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
进程,并且应该在Server
进程时调用匹配:DOWN
的handle_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())
调用监视器,但我不知道我还应该怎么做。
当你调用Temp.Monitor.monitor/1
方法时,它仍然是运行在Temp.Server
自己的进程中,而不是Temp.Monitor
的。这意味着当 Temp.Server
死亡时 :DOWN
消息被发送到 Temp.Server
,这是多余的。
您想要做的是,将您的服务器进程的 pid
传递给 Temp.Monitor
并让它从它自己的进程中调用 Process.Monitor
方法,以便它可以监视它。这只能发生在 GenServer callbacks.
之一
您可以通过将实施移至 handle_call/3
or 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
我遇到了 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
进程,并且应该在Server
进程时调用匹配:DOWN
的handle_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())
调用监视器,但我不知道我还应该怎么做。
当你调用Temp.Monitor.monitor/1
方法时,它仍然是运行在Temp.Server
自己的进程中,而不是Temp.Monitor
的。这意味着当 Temp.Server
死亡时 :DOWN
消息被发送到 Temp.Server
,这是多余的。
您想要做的是,将您的服务器进程的 pid
传递给 Temp.Monitor
并让它从它自己的进程中调用 Process.Monitor
方法,以便它可以监视它。这只能发生在 GenServer callbacks.
您可以通过将实施移至 handle_call/3
or 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