OTP & gen_server
OTP is a collection of behaviours (generic process patterns), libraries, and design principles:
27.1 What is OTP?
OTP is a collection of behaviours (generic process patterns), libraries, and design principles:
Behaviours: gen_server, gen_statem, gen_event, supervisor, application.
The generic part (message loop, timeouts, debugging, upgrades, system messages) is written once; you provide callback modules with the specific logic.
27.2 A complete gen_server
-module(kv_store).
-behaviour(gen_server).
%% API
-export([start_link/0, put/2, get/1, delete/1, stop/0]).
%% Callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
%%% ---------------- API ----------------
start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
put(Key, Value) -> gen_server:cast(?SERVER, {put, Key, Value}).
get(Key) -> gen_server:call(?SERVER, {get, Key}).
delete(Key) -> gen_server:call(?SERVER, {delete, Key}).
stop() -> gen_server:stop(?SERVER).
%%% ---------------- Callbacks ----------------
init([]) ->
process_flag(trap_exit, true), % so terminate/2 runs on supervisor shutdown
{ok, #{}}.
handle_call({get, Key}, _From, State) ->
{reply, maps:find(Key, State), State};
handle_call({delete, Key}, _From, State) ->
{reply, ok, maps:remove(Key, State)};
handle_call(_Unknown, _From, State) ->
{reply, {error, unknown_request}, State}.
handle_cast({put, Key, Value}, State) ->
{noreply, State#{Key => Value}}.
handle_info(Msg, State) ->
logger:warning("Unexpected message: ~p", [Msg]),
{noreply, State}.
terminate(_Reason, _State) -> ok.
…27.3 Callback reference
{ok, S}, {ok, S, Timeout | hibernate | {continue, C}}, {stop, R}, ignore
{reply, R, S}, {reply, R, S, Timeout}, {noreply, S}, {stop, Reason, R, S} {noreply, S}, {stop, Reason, S} {continue, C} {noreply, S}...
shutdown / stop sys:get_status, crash logs sanitized status map
Start variants: start/3,4, start_link/3,4, start_monitor/3,4. Names: {local, Name}, {global, Name}, {via, Module, Name}.
27.4 Deferred replies
handle_call(slow, From, State) ->
spawn(fun() -> gen_server:reply(From, compute()) end),
{noreply, State}.27.5 Asynchronous requests (OTP 23+)
ReqId = gen_server:send_request(Server, Request),
Reply = gen_server:wait_response(ReqId, 5000),
%% or gen_server:receive_response/2, check_response/2, reqids_* collections (OTP 25+)27.6 gen_server tips
One message at a time → potential bottleneck; keep callbacks fast.
Default call timeout: 5000 ms.
Never call yourself (deadlock).
Put business logic in pure functions; the gen_server only manages state and messages.