Brian Hicks
Brian Hicks

Reputation: 6403

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?

Upvotes: 7

Views: 692

Answers (2)

Paweł Obrok
Paweł Obrok

Reputation: 23164

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

Upvotes: 8

Pascal
Pascal

Reputation: 14042

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) └── ...

Upvotes: 5

Related Questions