# client api
def start_link(question_list) do
self() |> yellow
GenServer.start_link(__MODULE__, question_list)
end
def next(pid) do
GenServer.call(pid, :next)
end
def stop(pid) do
GenServer.stop(pid, :finished_quiz)
end
# server api
def init(qs_list \\ []) do
{:ok, qs_list}
end
def handle_call(:next, _from, []) do
{:reply, :terminate, []}
end
def handle_call(:next, _from, [question | remaining_qs_list]) do
{:reply, question, remaining_qs_list}
end
def terminate(:finished_quiz, _qs_list) do
Logger.info("QuizSend Genserver stopped.")
"finished quiz, exiting" |> orange
end
yellow and orange are IO.inspect with colors.
But strange part is
self() in start_link prints #PID<0.902.0>
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?
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
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.
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
ret
end