Newbie question about GenServer and Supervisor Behaviours

TL;DR By only given the pid for a supervisor and the client side(the APIs) of a child GenServer(The only parameter for those APIs are the pid of the child GenServer for sure, if still unclear, see the example below for Storage.get/1). Without naming the child process, running Supervisor.which_children/1 or switching to DynamicSupervisor + Supervisor.start_child/2. How do I get the pid of the child process programmatically upon calling Supervisor.start_link/1? How can I communicate with the child process?

I have a question regarding how to access the child pid given the supervisor. For example, I have a GenServer which is just in charge of storing a value and a Supervisor which supervises the GenServer, which looks like

Summary

`
defmodule Storage do
use GenServer

def start_link(init_value) do
GenServer.start_link(Storage, init_value, [])
end

def get(pid) do
GenServer.call(pid, :get)
end

def init(init_value) do
{:ok, init_value}
end

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

defmodule Storage.Supervisor do
use Supervisor

def start_link(_) do
Supervisor.start_link(MODULE, :ok)
end

def init(:ok) do
children = [
{Storage, 1}
]

Supervisor.init(children, [strategy: :one_for_one])

end
end
`

The problem is that, I can use Storage.Supervisor.start_link/1 to start the Supervisor but it’s returning {ok, <supervisor pid>} and I can’t send the child process any message with that pid. So far I’ve explored the following options:

  1. use name option in GenServer.init. However, that doesn’t work in my scenario when I want to spawn multiple Supervisors.
  2. use Supervisor.which_children/1. I think this might work but where should I call it? I just get a feeling that using it might not be the best practice.
  3. Switch to DynamicSupervisor and use Supervisor.start_child/2. However, I think since it’s a one for one supervisor. Do I really need to make it that complex by introducing things that I don’t really need?

So I’m wondering if there’s a way for Supervisor.init/1 to report back the child pids that it started? Or in that case, it’s impossible that I’ll either need to look it up by Supervisor.which_children/1 or using Supervisor.start_child/2? Any help is appreciated. Thanks!

You should use Registry if You have trouble finding processes. This allow to store a reference to a pid…

This is not done at the supervisor level, but each Genserver could use via_tuple function to register itself… and the Registry is cleaned when the process dies.

3 Likes

See Name Registration.

For example send/2 will accept either a pid or registered_name. When strictly a pid is needed you can use Process.whereis/1 to lookup the pid from the registered_name.

4 Likes