Strange GenServer - why two different pids?

I wrote a GenServer.

# client api
  def start_link(question_list) do
    self() |> yellow
    GenServer.start_link(__MODULE__, question_list)

  def next(pid) do, :next)

  def stop(pid) do
    GenServer.stop(pid, :finished_quiz)

  # server api

  def init(qs_list \\ []) do
    {:ok, qs_list}

  def handle_call(:next, _from, []) do
    {:reply, :terminate, []}

  def handle_call(:next, _from, [question | remaining_qs_list]) do
    {:reply, question, remaining_qs_list}

  def terminate(:finished_quiz, _qs_list) do"QuizSend Genserver stopped.")
    "finished quiz, exiting" |> orange

yellow and orange are IO.inspect with colors.

But strange part is

  1. self() in start_link prints #PID<0.902.0>
  2. when I call this genserver like QuestionsServer.start_link() |> yellow the reply is {:ok, #PID<0.906.0>}

Why two different pids? It must be one GenServer, right?

Additional info.

iex(3)> Process.alive?(,906,0))
iex(4)> Process.alive?(,902,0))

The self() in start_link/1 runs in the context of the process calling start_link and not in the newly created GenServer (since it wasn’t created yet).

So it prints the pid of the current process and returns the pid of the created GenServer


self() – which process is it? The one which called the GenServer?

Can I get the pid of the GenServer from inside GenServer? say, init function?

Yes, your start_link/1 is a function like any other. It is like calling:

def new_self do

Yes, init/1 is called in the GenServer process.

1 Like

Why two different pids? It must be one GenServer, right?

No. You can start as many GenServers of the same type as you want, they use the same code, but they are not the same process.

Your example reminded me of my first OOP lessons in University: you have a blue print for a car, that’s always the same, but when the cars come out of the factory, they all look the same - but they are not the same object. You can get into one car and drive, that does not influence the blueprint, or any of the other cars.

Same in this case. You can start GenServers all over the place, they will all have different process IDs, and different states, because they all have different processes.


It’s important to understand that start_link is not part of the GenServer behaviour. It is just a convention to name it that way. It is part of the client functions of your module, like next and stop so it executes within the caller’s process. Only the GenServer callbacks, as specified in the behaviour, execute within the GenServer process itself.


in my case, the command to start genserver was run only once.
So there must be only one genserver.

also, the self() in start_link dies after calling GenServer.start_link

So, self() is the caller;s pid.

I verified it. and this is indeed the case.

Thank you so much!

I would bet that the self() call is not affected. But you need to return the return value of GenServer.start_link from the start_link function. If you want to run self() after it, you need to do something like

def start_link(question_list) do
  ret = GenServer.start_link(__MODULE__, question_list)
  self() |> yellow