Intro
spawn
# pid = spawn(fun)
pid = spawn(fn -> IO.puts("Hello!") end)
pid = spawn_link(fn -> IO.puts("Hello!") end)
# pid = spawn(module, function, params)
pid = spawn(SomeModule, :some_function, [1, 2, 3])
pid = spawn_link(SomeModule, :some_function, [1, 2, 3])
send
send(pid, message)
receive
receive do
message -> IO.puts(message)
after
5000 -> IO.puts(:stderr, "No message in 5 seconds!")
end
GenServer
defmodule SomeServer do
use GenServer
@impl GenServer
def init(initial_state) do
{:ok, initial_state}
end
def start_link(_) do
{:ok, pid} = GenServer.start_link(module, initial_state, options)
end
def some_call(pid, msg) do
response = GenServer.call(pid, msg, timeout \\ 5000)
end
def some_cast do
:ok = GenServer.cast(pid, msg, timeout \\ 5000)
end
def reply do
:ok = GenServer.reply(from, msg)
end
end
start_link
{:ok, pid} = GenServer.start_link(module, initial_state, options)
Options
Name |
Description |
:name |
used for name registration |
:timeout |
time the server is allowed to spend on initialization |
handle_call callback
@impl GenServer
def handle_call(request, from, state) do
{:reply, response, new_state}
end
Responses
Name |
Description |
{:reply, reply, new_state} |
sends the response reply and continues the loop |
{:noreply, new_state} |
Does not send a response and continues the loop. The response must be sent with reply/2 |
handle_cast callback
@impl GenServer
def handle_cast(request, state) do
{:noreply, new_state}
end
handle_info callback
@impl GenServer
def handle_info(request, state) do
{:noreply, new_state}
end
handle_continue callback
@impl GenServer
def handle_continue(continue, state) do
{:noreply, new_state}
end
Elixir School - handle_continue
Exits
Trapping exits
Process.flag(:trap_exit, true)
{:EXIT, from_pid, exit_reason}
{reason, where}
Monitors
monitor_ref = Process.monitor(target_pid)
{:DONW, monitor_ref, :process, from_pid, exit_reason}
Process.demonitor(monitor_ref)
Supervisor
{:ok, supervisor_pid} = Supervisor.start_link(children, options)
Options
Name |
Description |
:strategy |
the supervision strategy |
:max_restarts |
maximum number of restarts allowed in a time frame. Default: 3 |
:max_seconds |
the time frame for :max_restarts . Default: 5 |
:name |
a name to register the supervisor process |
Strategies
Name |
Description |
:one_for_one |
only that process is restarted |
:one_for_all |
all other child processes are terminated and then all are restarted |
:rest_for_one |
the terminated child and the rest of the children started after ir are terminated and restarted |
Child specification
%{
id: Module,
start: {Module, :start_link, [nil]},
type: :worker,
restart: :permanent,
shutdown: 5_000
}
Options
Name |
Description |
:id |
identifies the child, defaults to the given module |
start |
tuple of mod, fun args |
:type |
Item Two |
restart |
defines when a terminated child process should be restarted, defaults to permanent |
shutdown |
defines how a child should be terminated |
Shutdown values
Name |
Description |
:brutal_kill |
child process is immediately terminated |
integer` |
the amount of time the supervisor will wait |
:infinity |
waits indefinitely |
Restart values
Name |
Description |
:permanent |
child process is always restarted |
:temporary |
child process is never restarted |
:transient |
child process is restarted only if it terminates abnormally |
Hexdocs - Child specification
With a module
defmodule Module do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, nil)
end
@impl Supervisor
def init(_) do
Supervisor.init(children, options)
end
end
Registry
{:ok, pid} = Registry.start_link(name: :my_registry, keys: :unique)
{:ok, pid} = Registry.register(:my_registry, {:my_worker, 1}, nil)
[{pid, value}] = Registry.lookup(:my_registry, {:my_worker, 1})
With a module
defmodule ModuleRegistry do
def start_link do
end
def via_tuple(key) do
{:via, Registry, {__MODULE__, key}}
end
def child_spec(_) do
Supervisor.child_spec(
Registry,
id: __MODULE__,
start: {__MODULE__, start_link, []}
)
end
end
Task
task = Task.async(fun)
Task.await(task)
Agent
{:ok, pid} = Agent.start_link(fun)
Agent.get(pid, fun)
:ok = Agent.update(pid, fun)
:ok = Agent.cast(pid, fun)