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)