1
votes

I am trying to create a dynamic supervisor to start child processes. There are three modules I am using to do this, one is the main module, the second one is the Dynamic Supervisor and the third is the genserver. I do not get any errors but I am not able to see any child processes running.

Here is my code. The first one is the module having the main method

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   

The following is a dynamic Supervisor

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

The following is the GenServers the worker is supposed to create

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

I expect the genserver to be running but I get The Persons started in main method are: %{active: 0, specs: 0, supervisors: 0, workers: 0}

I dont know why the supervisor is not able to start the genserver. Any help would be good. TIA

1
num_of_persons is not defined in start_persons(num_of_persons) in the Simulator.main/1. Please post the real code or provide a correct MCVE.Aleksei Matiushkin
My bad, Thanks for pointing that out. I was trying to explain in minimal terms. Here is my full code pastebin.com/2z33qhsX. Also this is one of helper modules pastebin.com/aZwmD9igThe_Lost_Avatar
I will check it a bit later if there won’t be an answer yet. Maybe try to Process.sleep(1_000) before checking the children? It’s not a direct child, the call is asynchronous, so there is no guarantee it will arise immediately.Aleksei Matiushkin
Yeah Sure, i couldnt find any children even after putting the process to sleep.The_Lost_Avatar
Check hexdocs.pm/elixir/Supervisor.html#module-child_spec-1 for the correct way to construct a child spec in the DynamicSupervisor; specifically, you'll need to do {Person, [private_key, public_key, num_of_counts]} and make sure the Person.start_link function can handle all those arguments.Yawar

1 Answers

5
votes

In your case you'll need to do three things:

Set up the child spec correctly before starting it from the DynamicSupervisor:

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

Force the child start to fail if it's not successful:

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

And, ensure that the child process can handle the exact arguments the supervisor gives it:

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