This is worth reading : [erlang-questions] The gen server simplified (how it works)
I made an Elixir version of the mini genserver for you, with small changes to demonstrate how handle_info works:
defmodule MiniGs do
def start_link(module, arg) do
pid = spawn_link(fn -> start(module, arg) end)
{:ok, pid}
end
def call(pid, request, timeout \\ 5000) do
ref = make_ref()
send(pid, {:minigs_call, self(), ref, request})
receive do
{^ref, reply} -> reply
after
timeout -> exit({:timeout, {MiniGs, :call, [pid, request, timeout]}})
end
end
defp start(module, arg) do
{:ok, state} = module.init(arg)
loop(module, state)
end
defp loop(module, state) do
receive do
{:minigs_call, from, ref, request} ->
{:reply, reply, new_state} = module.handle_call(request, from, state)
send(from, {ref, reply})
loop(module, new_state)
other_message ->
{:noreply, new_state} = module.handle_info(other_message, state)
loop(module, new_state)
end
end
end
defmodule Stack do
def start_link(base) when is_list(base) do
MiniGs.start_link(__MODULE__, base)
end
def push(pid, item) do
:ok = MiniGs.call(pid, {:push, item})
end
def pop(pid) do
MiniGs.call(pid, :pop)
end
def init(base) do
{:ok, _stack = base}
end
def handle_call({:push, item}, _from, stack) do
{:reply, :ok, [item | stack]}
end
def handle_call(:pop, _from, [item | stack]) do
{:reply, {:ok, item}, stack}
end
def handle_call(:pop, _from, []) do
{:reply, {:error, :empty}, []}
end
def handle_info(info, stack) do
IO.puts("got info: #{inspect(info)}")
{:noreply, stack}
end
end
{:ok, pid} = Stack.start_link([])
:ok = Stack.push(pid, 1)
:ok = Stack.push(pid, 2)
:ok = Stack.push(pid, 3)
{:ok, 3} = Stack.pop(pid)
{:ok, 2} = Stack.pop(pid)
{:ok, 1} = Stack.pop(pid)
send(pid, "hello")
{:error, :empty} = Stack.pop(pid)
As an exercise, you could try to implement the possibility to return timeout as in {:reply, reply, state, timeout}
and the mini gs would call module.handle_info(:timeout, state)