A gen_server
is a specific finite state machine working like a server. gen_server
can handle different type of event:
handle_call
handle_cast
handle_info
Synchronous and asynchronous message are specified in OTP and are simple tagged tuples with any kind of data on it.
A simple gen_server
is defined like this:
-module(simple_gen_server).
-behaviour(gen_server).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
start_link() ->
Return = gen_server:start_link({local, ?MODULE}, ?MODULE, [], []),
io:format("start_link: ~p~n", [Return]),
Return.
init([]) ->
State = [],
Return = {ok, State},
io:format("init: ~p~n", [State]),
Return.
handle_call(_Request, _From, State) ->
Reply = ok,
Return = {reply, Reply, State},
io:format("handle_call: ~p~n", [Return]),
Return.
handle_cast(_Msg, State) ->
Return = {noreply, State},
io:format("handle_cast: ~p~n", [Return]),
Return.
handle_info(_Info, State) ->
Return = {noreply, State},
io:format("handle_info: ~p~n", [Return]),
Return.
terminate(_Reason, _State) ->
Return = ok,
io:format("terminate: ~p~n", [Return]),
ok.
code_change(_OldVsn, State, _Extra) ->
Return = {ok, State},
io:format("code_change: ~p~n", [Return]),
Return.
This code is simple: every message received is printed to standard output.
To define a gen_server
, you need to explicitly declare it in your source code with -behaviour(gen_server)
. Note, behaviour
can be written in US (behavior) or UK (behaviour).
This function is a simple shortcut to call another function: gen_server:start_link/3,4
.
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
This function is called when you want to start your server linked to a supervisor
or another process. start_link/3,4
can register automatically your process (if you think your process need to be unique) or can simply spawn it like simple process. When called, this function execute init/1
.
This function can return these define values:
{ok,Pid}
ignore
{error,Error}
init([]) ->
State = [],
{ok, State}.
init/1
is the first executed function when your server will be launched. This one initialize all prerequisite of your application and return state to newly created process.
This function can return only these defined values:
{ok,State}
{ok,State,Timeout}
{ok,State,hibernate}
{stop,Reason}
ignore
State
variable can be everything, (e.g. list, tuple, proplists, map, record) and remain accessible to all function inside spawned process.
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
gen_server:call/2
execute this callback. The first argument is your message (_Request
), the second is the origin of the request (_From
) and the last one is the current state (State
) of your running gen_server behaviour.
If you want a reply to caller, handle_call/3
need to return one of these data structure:
{reply,Reply,NewState}
{reply,Reply,NewState,Timeout}
{reply,Reply,NewState,hibernate}
If you want no reply to caller, handle_call/3
need to return one of these data structure:
{noreply,NewState}
{noreply,NewState,Timeout}
{noreply,NewState,hibernate}
If you want to stop the current execution of your current gen_server, handle_call/3
need to return one of these data structure:
{stop,Reason,Reply,NewState}
{stop,Reason,NewState}
handle_cast(_Msg, State) ->
{noreply, State}.
gen_server:cast/2
execute this callback. The first argument is your message (_Msg
), and the second the current state of your running gen_server behaviour.
By default, this function can't data to the caller, so, you have only two choices, continue current execution:
{noreply,NewState}
{noreply,NewState,Timeout}
{noreply,NewState,hibernate}
Or stop your current gen_server
process:
{stop,Reason,NewState}
handle_info(_Info, State) ->
{noreply, State}.
handle_info/2
is executed when non-standard OTP message come from outside world. This one can't reply and, like handle_cast/2
can do only 2 actions, continuing current execution:
{noreply,NewState}
{noreply,NewState,Timeout}
{noreply,NewState,hibernate}
Or stop the current running gen_server
process:
{stop,Reason,NewState}
terminate(_Reason, _State) ->
ok.
terminate/2
is called when an error occur or when you want to shutdown your gen_server
process.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
code_change/3
function is called when you want to upgrade your running code.
This function can return only these defined values:
{ok, NewState}
{error, Reason}
You can compile your code and start simple_gen_server
:
simple_gen_server:start_link().
If you want to send message to your server, you can use these functions:
% will use handle_call as callback and print:
% handle_call: mymessage
gen_server:call(simple_gen_server, mymessage).
% will use handle_cast as callback and print:
% handle_cast: mymessage
gen_server:cast(simple_gen_server, mymessage).
% will use handle_info as callback and print:
% handle_info: mymessage
erlang:send(whereis(simple_gen_server), mymessage).