Best practices for connecting Supervisor's child processes to each other

I am trying to figure out if there’s an established best practice for connecting child processes within the same supervisor without using name registration.

I have the following processes

  • PortCache
  • StateServer
  • WebServer - requires a PortCache and StateServer for startup

I am using a rest_for_one supervision strategy and trying to create a supervision tree like this.

I’m curious what the best way is to give WebServer a way to send messages to PortCache and WebServer without using name registration.

Here is what I currently have:

defmodule MyApp.Supervisor do

  def start_link(_init_opt) do
    # Start the supervisor with no children
    with {:ok, sup} <- Supervisor.start_link([], strategy: :rest_for_one) do
      {:ok, port_cache} = Supervisor.start_child(sup, PortCache)
      {:ok, state_server} = Supervisor.start_child(sup, StateServer)

      {:ok, _web_server} = 
        Supervisor.start_child(sup, {
          WebServer, 
          port_cache: port_cache, 
          state_server: state_server
         })

       {:ok, sup}
    end
  end
end

I know generally we pass a list of children to a supervisor, but then we don’t have a way to reference the other process’s pids. Are there drawbacks to this approach or a better way of doing this?

1 Like

An alternative (not necessarily better) is using the WebServer as the interface for the Supervisor. What I mean is first you’d start the Supervisor, then start the WebServer as a child and pass the Supervisor’s pid to the WebServer. Then implement a WebServer.start_child function. The WebServer could then call out to the Supervisor to start the child process, store the child’s pid in it’s state, as well as link them, etc.

I don’t see a ton of benefit compared to what you have unless you need to start different child types in different scenarios, like if you have different implementations for the StateServer depending on configuration values or you have a complex chain of processes.

EDIT: This would move the WebServer as the first child, and might not work well with the rest_for_one requirement (I missed that on first read).

I would do something similar, but not with WebServer, with an additional GenServer used to start others processes, and keeping pid in his state.

I guess I am a little bit influenced by how poolboy does this.

2 Likes

Why not name registration?

Maybe overkill but what about Registry? Start a registry named MyApp.Supervisor.Registry in your MyApp.Supervisor before anything else and then each supervised process can register itself in init and dispatch calls via the registry.

1 Like