Why do we put the name of the module as child instead of GenServer name in a Supervisor?

I’ve been following the book Programming Elixir and there’s this GenServer below as part of an app:

defmodule Duper.Gatherer do
  use GenServer

  @me Gatherer

  def start_link(worker_count) do
    GenServer.start_link(__MODULE__, worker_count, name: @me)

So our GenServer's name is Gatherer.

And then how we add this GenServer to our supervision tree is:

  def start(_type, _args) do
    children = [
      {Duper.Gatherer, 50}

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_all, name: Duper.Supervisor]
    Supervisor.start_link(children, opts)

So if we check the docs for start_link/3 it says,

Starts a GenServer process linked to the current process.

What I couldn’t get is if our GenServer is called Gatherer why do we add the module name to the children list instead of the GenServer name?

Another thing is when I checked the source code for GenServer.start_link/3 I see this called

    do_start(:link, module, init_arg, options)

I don’t really know what link there really means but it reminds me of Process.link/1 so if we link two processes then they’re informed about each other’s exits, right? So how does Supervisor handle the exit of child apps so that it doesn’t crash when a child app exits?

Sorry if my questions are stupid, as it’s quite late here and my brain can’t process things anymore. :smiley: I just didn’t want to forget the questions, so I’ll take a look at my questions tomorrow again and edit if necessary.

There is a difference between the module name, used in the supervision tree, and the name by which You can find a process. BTW Duper.Gatherer is not equal to Gatherer, You can also use Registry to give a name.

You might often see

name: __MODULE__

But it could be any atom.

Supervisor traps exits, and thus… don’t die.

Process.flag(:trap_exit, true)

To really get a good understanding of the GenServer/Supervisor paradigm, I urge you to read the erlang doc here:
on top of the Elixir doc.

In erlang, each supervised process has an id, which is how the supervisor find it, and optionally a name, which can be used as an alias to find it from everywhere else. id is local to the supervisor, name is local to the node. In the simplest case they are the same as the GenServer module name but each can be customized.

Elixir adds a couple of convenience touches on top of that:

  1. the child_spec/1 function and the shorthand format in children list, and
  2. the Registry module for dynamically named process.

So we pass in the module which is supposed to start the GenServer, hence supervisor can get the PID of it as a result of calling start_link, and the name of the GenServer is actually how any other process can communicate with it instead of using the PID directly, is that right?

1 Like

Yes, because the pid can change, it’s easier to get a process by name.

There are local and global registries, to help for distributed systems.


Thank you for the link, I’ll read it whenever I can. By the way there’s this

:gen.start(:gen_server, link, module, init_arg, opts)

in gen_server.ex.

However I couldn’t find any documentation regarding :gen in Erlang docs. Only thing I could find is Erlang -- gen_server

What’s that :gen atom? or where can I find more information about it?

:gen is considered internal API; it is basically the extraction of common functions among several :gen_* modules.

1 Like

Yes, the :gen module is internal and is not documented so you should never call it yourself. It is a little strange that gen_server.ex makes this call instead of

:gen_server.start_link(module, init_arg, opts)

as this is just a wrapper to the call :gen.start but a little more clearly explict.


Note that named GenServers must be unique per node (there is a different system for unique-per-cluster). So only use this for singleton GenServers. It’s kind of like DNS.

1 Like