gen_server(3)

MODULE
gen_server - A Generic Client-Server Behaviour

DESCRIPTION

This module provides a standard way of writing Client-Server applications. All servers written as generic servers share a common set of interface functions. The generic parts of the server contain functions for debugging, handling the termination of the parent, and presentation of illustrative error information if something goes wrong with the server.

The idea is that the implementation specific parts of a client-server is in one module, called the callback module. The callback module contains the client interface functions which use the server access functions described below. The callback module also contains the server callback functions, for example handle_call/3. Whenever the generic part of the server receives a message - sent through a server access function, for example - the corresponding callback function is called.

The relationship between the generic interface functions (and received messages) and the callback functions can be illustrated as follows:
Callback module               gen_server
----------------               ----------
gen_server:start      ----->   start a new server
Module:init/1         <-----
                               looping
gen_server:call       ----->
Module:handle_call/3  <-----
gen_server:cast       ----->
Module:handle_cast/2  <-----
gen_server:multi_call ----->
Module:handle_call/3  <-----
gen_server:abcast     ----->
Module:handle_cast/2  <-----
Module:handle_info/2  <-----  other message
                              received.
Module:terminate/2    <-----  clean up before
                              termination.

If the server wants to trap exit signals, this must be explicitly initiated in the callback module.

An instance of the gen_server behaviour can be debugged using the module sys.

EXPORTS

start(Module, Args, Options) -> ServerRet
start(ServerName, Module, Args, Options) -> ServerRet
start_link(Module, Args, Options) -> ServerRet
start_link(ServerName, Module, Args, Options) -> ServerRet

    Types
        Module = atom()
        ServerName = {local, atom()} | {global, atom()}
        Args = term()
        Options = [Opt]
        Opt = {debug, [Dbg]} | {timeout, Time}
        Dbg = trace | log | statistics | {log_to_file, FileName} | {install, {Func, FuncState}}
        ServerRet = {ok, Pid} | ignore | {error, Reason}
        Pid = pid()
        Reason = {already_started, Pid} | term()

    Starts a new server. If the server is started without ServerName, it can only be called using the returned Pid identifier. If started with ServerName, the name is registered locally or globally.

    Module is the name of the callback module.

    A server started with start/3 or start/4 does not care about the parent, which means that the parent is not handled explicitly in the generic process part. If started in this manner, these functions must not be used if the server is a worker in a supervision tree.

    A server started with start_link/3 or start_link/4 is initially linked to the caller, the parent, and it will terminate whenever the parent process terminates, and with the same reason as the parent. If the server traps exits, the terminate/2 callback function is called in order to clean up before the termination. If started in this manner, these functions should be used if the server is a worker in a supervision tree.

    Time specifies how long time, in milliseconds, the server is allowed to spend initializing.

    The function Module:init(Args) is called in the new process in order to initialize the server (see below).

    Refer to the sys module for more information about the Dbg options.

call(ServerRef, Request) -> Reply
call(ServerRef, Request, Timeout) -> Reply

    Types
        ServerRef = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Request = term()
        Timeout = int() > 0 | infinity
        Reply = term()

    A request is sent to the ServerRef server. The request can be any term, but the term must be recognized by the server. The request is handled by the server (in the Module:handle_call/2 function) and the client is suspended while waiting for the response. Timeout should be set to some reasonable value in milliseconds. The special value infinity can be used if the user has no idea how long the request is supposed to take. The default value is 5000 if Timeout is not specified.

    If Timeout has an integer value and no response has been delivered within Timeout milliseconds, then the client terminates with reason {timeout, {gen_server, call, [ServerRef, Request, Timeout]}}.

cast(ServerRef, Request) -> ok

    Types
        ServerRef = Name | {Name, Node} | {global, Name} | Pid
        Name = atom()
        Node = atom()
        Request = term()

    A request is sent to the server. As no response will be delivered, the client making the cast is not suspended until the request has been handled by the server. This function returns ok immediately and ignores non-existing servers.

multi_call(DistRef, Request) -> DistRep
multi_call(Nodes, DistRef, Request) -> DistRep

    Types
        Nodes = [Node]
        Node = atom()
        DistRef = atom()
        DistRep = {[{Node, Reply}], [Node]}
        Request = term()
        Reply = term()

    Sends a request to the locally registered server DistRef at every known node (or Nodes). This function returns a list of replies which are tagged with the corresponding node name, and a list of bad nodes. Reply is the value returned by a server. A node is marked bad if the server at a specific node, or the node itself, does not exist.

    The request is sent to the DistRef server at all nodes before the replies are collected. This ensures that the request is handled in parallel on all nodes. If no reply is received during the collection of replies, the existence of a server at a specific node is checked. This function hangs if the server was started after the request was sent, but before the existence check was performed

abcast(DistRef, Request) -> abcast
abcast(Nodes, DistRef, Request) -> abcast

    Types
        Nodes = [Node]
        Node = atom()
        DistRef = atom()
        Request = term()

    Broadcasts the request asynchronously to the locally registered server DistRef on every known node (or Nodes). This function returns immediately and ignores non-existing servers or nodes.

reply(To, Reply) -> true

    Types
        To = {pid(), Tag}
        Tag = term()

    This function can be used by a server to make an explicit reply, if a reply cannot be returned immediately as the return value of Module:handle_call/3. To has the same value as the From argument in Module:handle_call/3.

Callback Functions

The following functions should be exported from a gen_server callback module.

EXPORTS

Module:init(Args) -> {ok, State} | {ok, State, Timeout} | ignore | {stop, StopReason}

    Types
        Args = term()
        State = term()
        Timeout = int() >= 0 | infinity
        StopReason = term()

    Whenever a new server is started, init/1 is the first function called in the specified callback module. To ensure a synchronized start-up procedure, the gen_server:start function will not return before the init/1 function has returned.

    The Args argument supplied to the init/1 function is the same as the Args parameter supplied to the gen_server:start functions.

    The purpose of the init/1 function is to initialize the server and the internal state of the server. A server which holds an external resource typically opens the associated port and keeps the port identity in the internal state.

    If the server wants to trap exits, this has to be expressed explicitly in the init function with process_flag(trap_exit, true).

    The representation of the server State is an implementation specific detail which must be decided by the designer of the server. State will be visible as an argument to all callback functions. To change something in State, a new value is returned from the callback function using the return values (terms) described below.

    If the initializing procedure fails, the reason is supplied as StopReason with the {stop, StopReason} return value.

    After the server has been successfully initialized, the generic part of the server enters the main loop and waits for requests. A Timeout time can be specified if the server is only allowed to wait for a certain time for the next event. If the timeout time elapses, the special timeout message should be handled in the Module:handle_info/2 callback function. Timeout is specified in milliseconds.

    This function can return ignore in order to inform the parent, especially if it is a supervisor, that the server, as an example, did not start in accordance with the configuration data.

Module:handle_call(Request, From, State) -> CallReply

    Types
        Request = term()
        From = {pid(), Tag}
        Tag = term()
        CallReply = {reply, Reply, State} | {reply, Reply, State, Timeout} | {noreply, State} | {noreply, State, Timeout} | {stop, StopReason, Reply, State} | {stop, StopReason, State}
        Timeout = int() >= 0 | infinity
        StopReason = normal | shutdown | term()

    Whenever a client function has called one of the interface functions gen_server:call or gen_server:multi_call, the server handles the request in this callback function.

    Request is the same as the term supplied with the above client call. The server decides if the client should be sent a reply directly ({reply, ...}), indirectly ({noreply, ...}), or if the server has to terminate ({stop, ...}) as a result of the request. If {noreply, ...} is returned, a reply is sent to the client using the reply/2 function.

    If StopReason is something other than normal or shutdown, the server is assumed to have terminated with a runtime error. In this case, a lot of information is reported about the failure. The atom normal causes a normal termination of the server, while shutdown causes an abnormal, but faultless, termination.

    If the server decided to terminate {stop, StopReason [, ...]}, the Module:terminate/2 function is called. All code which handles the clean up before the server terminates should be located in the terminate function. The server will terminate due to StopReason.

    As described above ( see init/1), a timeout can be specified to take some specific action if no more requests are received within Timeout milliseconds.

Module:handle_cast(Request, State) -> Return

    Types
        Request = term()
        State = term()
        Return = {noreply, State} | {noreply, State, Timeout} | {stop, StopReason, State}
        Timeout = int() >= 0 | infinity
        StopReason = normal | shutdown | term()

    Whenever a client function has called one of the interface functions gen_server:cast or gen_server:abcast, the server handles the request in this callback function. No reply will ever be sent to the client, but the server can decide to terminate. StopReason is as described for handle_call/3.

Module:handle_info(Info, State) -> Return

    Types
        Info = term()
        State = term()
        Return = {noreply, State} | {noreply, State, Timeout} | {stop, StopReason, State}
        Timeout = int() >= 0 | infinity
        StopReason = normal | shutdown | term()

    This callback function handles received messages other than call and cast. Typical messages which are handled by this function include:

        {'EXIT', Pid, Reason}:
            If the process traps exit signals, the corresponding messages are handled here.

        {nodedown, Node}:
            If another Erlang node is monitored, the corresponding nodedown message is handled here.

        timeout:
            If Timeout milliseconds has elapsed since the last handled event, this message should be handled.

        Msg:
            All other messages which are sent to the server using Server ! Msg are also handled here.

  Note:

Communication with the server should always go through the interface functions described above.

The Return value is the same as for handle_cast/2. StopReason is as described for handle_call/3.

Module:terminate(Reason, State) -> ok

    Types
        Reason = term()
        State = term()

    This callback function is called whenever the server is about to terminate. Either one of the above callback functions have returned {stop, StopReason, ...}, in which case Reason is equal to StopReason; or some other fault has been caught. Reason is any term which describes the termination reason. If the server traps exits, the terminate function is called if the server's parent (normally a supervisor) dies or orders the server to die. If the server does not trap exits, it dies immediately if the parent dies.

    With this function, the server can clean up before the process terminates. It can, for example, de-allocate external resources.

    The termination reason cannot be changed here. The server will terminate due toReason regardless of what was returned from this function.

Module:code_change(OldVsn, State, Extra) -> {ok, NewState}

    Types
        OldVsn = undefined | term()
        State = term()
        Extra = term()
        NewState = term()

    This function is called when a code change is performed, which implies that the internal data structures of the server has changed. This function is supposed to convert the old state to the new one. OldVsn is the vsn attribute of the old version of the module. If no such attribute was defined, the atom undefined is sent. Extra is an optional term which is typically defined in the release upgrade script.

System Events

The gen_server behaviour generates the following system events, handled by the sys module:

    *   {in, Msg} when a message is received.

    *   {out, Msg, To} when a message is sent.

    *   {noreply, State} when no reply is delivered.

Example

The following example implements a simple queue server. The server has four interface functions:

    *   start/0 which starts the queue server.

    *   stop/0 which stops the queue server.

    *   in/1 which inserts an item last in the queue.

    *   out/0 which removes the oldest item from the queue.

The queue server is not linked to the parent process and the server does not handle the termination of the parent process explicitly.
-module(queue_serv).
-behaviour(gen_server).
%% External exports
-export([start/0, in/1, out/0, stop/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2]).
start() ->  gen_server:start({local, queue_serv},
                             queue_serv, [], []).
in(Item) -> gen_server:call(queue_serv, {in, Item}).
out() -> gen_server:call(queue_serv, out).
stop() -> gen_server:call(queue_serv, stop).
%% Callback functions.
init([]) ->
    {ok, {[],[]}}.
handle_call({in, X}, _From, {In, Out}) ->
    {reply, ok, {[X|In], Out}};
handle_call(out, _From, Queue) ->
    {Reply, NewQueue} = out(Queue),
    {reply, Reply, NewQueue};
handle_call(stop, _From, Queue) ->
    {stop, normal, ok, Queue}.
handle_cast(_, State) ->
    {noreply, State}.
handle_info(_, State) ->
    {noreply, State}.
terminate(Reason, State) ->
    ok.
%% Internal functions
out({In, [H|Out]}) ->
    {{value, H}, {In, Out}};
out({[], []}) ->
    {empty, {[],[]}};
out({In, _}) ->
    out({[], lists:reverse(In)}).

See Also

sys(3)

AUTHORS
Magnus Froberg - magnus@cslab.ericsson.se
Martin Bjorklund - mbj@erlang.ericsson.se