Elixir:使用Dynamic Supervisor启动孩子的正确方法

时间:2018-12-13 17:30:41

标签: elixir supervisor gen-server

我正在尝试创建一个动态主管来启动子进程。为此,我使用了三个模块,一个是主模块,第二个是Dynamic Supervisor,第三个是genserver。我没有收到任何错误,但看不到任何子进程正在运行。

这是我的代码。第一个是具有主要方法的模块

defmodule Simulator do
    def main(args) do
        {:ok, super_pid} = PersonManager.start_link(args)
        num_of_persons = 1
        start_persons(num_of_persons)
        IO.inspect PersonManager.count_children, label: "The Persons started in main method are"
    end

    def start_persons(num_of_persons) when num_of_persons >=1 do
        PersonManager.add_node(private_key, public_key, 0)
        start_persons(num_of_persons-1)    
    end
    # num_of_persons == 0 case handled
end   

以下是动态的主管

defmodule PersonManager do
  use DynamicSupervisor

  def start_link(args) do
    DynamicSupervisor.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def add_node(private_key, public_key, num_of_coins) do
    # The code flow does come here, used inspect to check
    child_spec = {Person, {private_key, public_key, num_of_coins}}
    DynamicSupervisor.start_child(__MODULE__, child_spec)
    #The code flow does come here, used inpect to check.   
  end
end

以下是该工作人员应该创建的GenServers

defmodule Person do
  use GenServer

  def init({private_key, public_key, address, num_of_coins}) do
    IO.puts "Starting a person"
    {:ok, %{private_key: private_key, public_key: public_key, num_of_coins: num_of_coins}}
  end

  def start_link({private_key, public_key, address, num_of_coins}) do
    IO.puts "Starting a person"
    GenServer.start_link(
      __MODULE__,
      {private_key, public_key, address, num_of_coins}
      name: {:global, "node:#{public_key}"},
    )
  end
end

我希望genserver正在运行,但是我得到The Persons started in main method are: %{active: 0, specs: 0, supervisors: 0, workers: 0}

我不知道为什么主管无法启动genserver。 任何帮助都会很好。 TIA

1 个答案:

答案 0 :(得分:3)

对于您而言,您需要做三件事:

在从DynamicSupervisor启动子规范之前正确设置子规范:

child_spec = {Person, [private_key, public_key, num_of_coins]}

如果子项不成功,则强制其开始失败:

case DynamicSupervisor.start_child do
  {:ok, _pid} -> {}
  {:error, {:already_started, _pid}} -> {}
  error -> raise error
end

并且,请确保子进程可以处理主管为其指定的确切参数:

defmodule Person do
  use GenServer

  def start_link([], private_key, public_key, num_of_coins) do
    GenServer.start_link(
      __MODULE__,
      {private_key, public_key, num_of_coins},
      name: {:global, "node:#{public_key}"}
    )
  end

  def init({private_key, public_key, num_of_coins}) do
    {:ok, %{private_key: private_key, public_key: public_key, num_of_coins: num_of_coins}}
  end
end