BEAM行为在两个节点之间进行RPC调用

时间:2017-06-21 09:22:10

标签: erlang elixir gen-server

我有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-CCtrl-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.disconnectCtrl-C Ctrl-C杀死A时,它会按预期工作...

PS 3 我认为它可能来自我调用的事实:start_link,但我有相同的行为:start(没有链接)

附属问题 Hynek -Pichi- Vychodil在评论中回答......

为什么在GenServer技术上在B上运行时,所有IO.put都打印在A上?

1 个答案:

答案 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语法,所以我不提供代码。