Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a sibling process in Elixir

I have an Elixir/Erlang process tree:

parent (Supervisor)
├── child1 (GenServer)
└── child2 (GenServer)

child1 (a DB client) has information that child2 needs to use. What's a good way to pass a reference from the Supervisor process to child2 so that child2 will always have a valid reference to child1? Do I just need to restructure my app so that child2 is supervised by child1?

like image 302
Brian Hicks Avatar asked Jun 07 '15 00:06

Brian Hicks


2 Answers

The simplest way would probably be for child1 and child2 to be registered under local aliases. You can do that while starting your GenServer by passing the name option:

defmodule Child1 do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end
end

In this case a process backed by the Child1 module will be registered locally under an alias Child1. Then if you want to send it messages you can use that alias instead of a PID.

defmodule Child1 do
  # ...

  def get_data do
    GenServer.call(__MODULE__, :get_data)
  end

  def handle_call(:get_data, _from, state) do
    {:reply, extract_data_from_state(state), state}
  end
end

If you want a more complex solution where for example many different processes of the same type may be registered, take a look at the gproc library

like image 77
Paweł Obrok Avatar answered Oct 07 '22 08:10

Paweł Obrok


I don't use Elixir, but I use Erlang, and I think that my answer is valid in both cases.

If your processes of type child1 are permanent, and in fixed number, then the simplest solution is to register them (game_server, event_server, ...)

But if they have transient life, their number is not fixed, or many process of the same kind will exist (a player process in a game for example) I suggest to use another organization:

  • The top level supervisor starts 2 processes, one server and one supervisor.
  • The server, at least, will maintain a list of all the living "child1" processes with some characteristics (player ID ...) that allow to access them. Generally it will also use the supervisor process to start, kill ... the "child1" processes.
  • The supervisor is a simple factory that will create and supervise the "child1", using a simple_one_for_one strategy.

    parent (Supervisor) ├── child2 (GenServer) └── Client_supervisor(Supervisor) ├── Client_server(registered GenServer) └── Client_factory(registered Supervisor) ├── Child1(GenServer) ├── Child1'(GenServer) └── ...

like image 25
Pascal Avatar answered Oct 07 '22 08:10

Pascal