Warum OTP?
Die Open Telecom Platform (OTP) ist das Rahmenwerk, das Erlang-Systeme robust macht: fertige Prozessmuster (Behaviours) für Server (gen_server), Zustandsautomaten (gen_statem), Ereignisse (gen_event) und Supervisor-Bäume, die abgestürzte Prozesse neu starten.
gen_server
Ein gen_server kapselt Zustand und beantwortet Anfragen. Er besteht aus Callback-Funktionen:
-behaviour(gen_server).
-export([main/1, init/1, handle_call/3, handle_cast/2]).
init(Start) -> {ok, Start}.
handle_call(stand, _Von, N) -> {reply, N, N};
handle_call({addiere, X}, _Von, N) -> {reply, N + X, N + X}.
handle_cast(zuruecksetzen, _N) -> {noreply, 0};
handle_cast({erhoehe, X}, N) -> {noreply, N + X}.
main(_) ->
{ok, Pid} = gen_server:start_link(?MODULE, 10, []),
io:format("~p~n", [gen_server:call(Pid, stand)]),
io:format("~p~n", [gen_server:call(Pid, {addiere, 5})]),
gen_server:cast(Pid, {erhoehe, 100}),
io:format("~p~n", [gen_server:call(Pid, stand)]),
gen_server:cast(Pid, zuruecksetzen),
io:format("~p~n", [gen_server:call(Pid, stand)]),
gen_server:stop(Pid).10 15 115 0
call ist synchron (wartet auf Antwort), cast asynchron.
Supervisor
Ein Supervisor überwacht Kindprozesse und startet sie nach einem Absturz gemäß einer Strategie neu:
-behaviour(supervisor).
-export([main/1, init/1, start_arbeiter/0]).
init(_) ->
Strategie = #{strategy => one_for_one, intensity => 5, period => 10},
Kinder = [#{id => arbeiter, start => {?MODULE, start_arbeiter, []}, restart => permanent}],
{ok, {Strategie, Kinder}}.
start_arbeiter() ->
Pid = spawn_link(fun() -> schleife() end),
register(arbeiter, Pid),
{ok, Pid}.
schleife() ->
receive
{Von, ping} -> Von ! pong, schleife();
absturz -> exit(boom)
end.
main(_) ->
logger:set_primary_config(level, none),
{ok, Sup} = supervisor:start_link(?MODULE, []),
Erster = whereis(arbeiter),
arbeiter ! {self(), ping},
receive pong -> io:format("pong~n") end,
unlink(Sup),
arbeiter ! absturz,
timer:sleep(100),
Zweiter = whereis(arbeiter),
io:format("neu gestartet: ~p~n", [Erster =/= Zweiter]),
arbeiter ! {self(), ping},
receive pong -> io:format("pong nach Neustart~n") end,
exit(Sup, shutdown).pong neu gestartet: true pong nach Neustart
Strategien
| Strategie | Wirkung |
|---|---|
one_for_one | Nur das abgestürzte Kind wird neu gestartet |
one_for_all | Alle Kinder werden neu gestartet |
rest_for_one | Das abgestürzte und alle danach gestarteten Kinder |
simple_one_for_one / dynamic | Viele gleichartige, dynamisch gestartete Kinder |
Merke
gen_serverkapselt Zustand mitinit,handle_callundhandle_cast- Supervisor starten Kinder nach Abstürzen neu
- Strategien:
one_for_one,one_for_all,rest_for_one - OTP-Anwendungen werden mit rebar3 gebaut und als Releases ausgeliefert
Aufgabe
Baue einen gen_server, der Schlüssel-Wert-Paare speichert (put/get).