Elixir School - Advanced
OTP Concurrency
GenServer
A module that implements a GenServer
behaviour is an OTP Server
To implement the GenServer
behaviour add this contract via the use
macro
GenServer
‘s can have both sync and async functions to handle requests
sync: GenServer.handle_call/3
async: GenServer.handle_cast/3
defmodule SimpleQueue do
use GenServer
@doc """
Start our queue and link it.
This is a helper function
"""
def start_link(state \\ []) do
GenServer.start_link(__MODULE__, state, name: __MODULE__)
end
@doc """
GenServer.init/1 callback
"""
def init(state), do: {:ok, state}
def handle_call(:dequeue, _from, [value | state]) do
{:reply, value, state}
end
def handle_call(:dequeue, _from, []) do
{:reply, nil, []}
end
def handle_call(:queue, _from, state) do
{:reply, state, state}
end
@doc """
GenServer.handle_cast/2 callback
"""
def handle_cast({:enqueue, value}, state) do
{:noreply, state ++ [value]}
end
def queue, do: GenServer.call(__MODULE__, :queue)
def enqueue(value), do: GenServer.cast(__MODULE__, {:enqueue, value})
def dequeue, do: GenServer.call(__MODULE__, :dequeue)
end
State the queue server
# {:ok, sqpid} = SimpleQueue.start_link([1, 2, 3])
Remove the next number from the queue
# SimpleQueue.dequeue()
Inspect the current queue
# SimpleQueue.queue()
Add a number to the queue
# SimpleQueue.enqueue(3)
Kill server
# Process.exit(sqpid, :kill)
OTP Supervisors
Supervisors are specialize processes that montior other processes
Enables fault tolerant programming through child process restart on failure
{:ok, app_pid} =
Supervisor.start_link(
[{SimpleQueue, [1, 2, 3]}],
strategy: :one_for_one,
name: SimpleQueue.Supervisor
)
# SimpleQueue.queue
# Process.exit(app_pid, :kill)