我有2个节点,
让我们称他们为A和B.
B有一个GenServer模块,启动时监控A.(此模块仅存在于B上) 当A连接到B时,此GenServer由A启动。
如果A在连接到B时死亡,B应该使用:init.stop()
这里是GenServer的代码:
defmodule Monitor do
use GenServer
def start_link() do
GenServer.start_link(__MODULE__, [], [])
end
def init([]) do
{:ok, %{}, 0}
end
def handle_info(:timeout, s) do
start(:"A@127.0.0.1")
{:noreply, s}
end
def handle_info({:nodedown, node}, state) do
s_node = node |> to_string
case s_node do
"A" <> _ ->
IO.puts "A is down, killing myself !"
:init.stop()
_ ->
:ko
end
{:noreply, state}
end
def handle_info(_, s) do
{:noreply, s}
end
def start(node) do
res = Node.monitor(node, true)
IO.puts "Starting to monitor: #{inspect node}"
end
end
我启动节点A和B.我将A连接到B.我在A中使用此命令启动Monitor:
> :rpc.call(:"B@127.0.0.1", Monitor, :start_link, [])
{:ok, #PID<8440.594.0>}
如果我用Node.disconnect
优雅地从B断开A,一切都按预期工作,B正在检测节点A并且正在自杀。
但是,如果我用Ctrl-C Ctrl-C
或Ctrl-g / q
杀死A的控制台
具有pid <0.594.0>
的B上的GenServer不再存在,因此无法检测到A已关闭。
是Pid&#34;链接&#34;出于某种原因来到A?
PS
我尝试使用Node.spawn
并在:rpc.call中调用spawn,得到相同的结果
PS 2
如果我从B控制台启动GenServer,当使用Node.disconnect
或Ctrl-C Ctrl-C
杀死A时,它会按预期工作...
PS 3 我认为它可能来自我调用的事实:start_link,但我有相同的行为:start(没有链接)
附属问题
Hynek -Pichi- Vychodil
在评论中回答......
为什么在GenServer技术上在B上运行时,所有IO.put都打印在A上?
答案 0 :(得分:0)
当您致电:rpc.call(:"B@127.0.0.1", Monitor, :start_link, [])
时,您将Monitor
流程与当前shell相关联(并将group_leader
设置为:user
A
进程,这基本上可以防止一旦A关闭,你就会看到输出IO.puts "A is down, killing myself !"
。)所以这意味着当A死在A处运行的shell时,你的Monitor
也会因为链接而死。
首先,您应该使用GenServer.start()
从:rpc.call()
开始,或者将进程标志:trap_exit
设置为true,或者将其放在运行在节点B的应用程序的超级用户树中。第二,在节点B处将group_leader
设置为user
进程。
P.S。:我不熟悉Elixir语法,所以我不提供代码。