Search code examples
erlangerlang-otpgen-server

Why does my gen_server implementation give a timeout?


I am trying to learn Erlang and OTP, and so I am currently trying to get a handle on gen_server.

I wrote a quick gen_server implementation of:

-module(test).
-behavior(gen_server).

%% API
-export([start/0, add/1]).
-export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]).

start() -> gen_server:start_link(?MODULE, [], []).
add(Value) -> gen_server:call(self(), {add, Value}).

%% Gen_Server
init(_Arguments) ->  {ok, []}.
terminate(_Reason, _State) -> ok.
code_change(_PreviousVersion, State, _) -> {ok, State}.

handle_call({add, Value}, _From, State) -> {reply, ok, [Value|State]}.
handle_cast(_Arg0, State) ->  {noreply, State}.
handle_info(Info, State) -> io:format("Unexpected message: ~p~n",[Info]), {noreply, State}.

The problem with this is the add/1 call is timing out instead of returning ok:

1> {ok, Pid} = test:start().
{ok,<0.33.0>}
2> Pid ! abc.
Unexpected message: abc
abc
3> test:add(3).
** exception exit: {timeout,{gen_server,call,[<0.31.0>,{add,3}]}}
     in function  gen_server:call/2 (gen_server.erl, line 204)
4> Pid ! abc.
abc

What am I doing wrong? It looks like the server is no longer running when I run gen_server:call/2.


Solution

  • You are passing in self() as the pid for the gen_server in test:add, that's not correct. self() will evaluate to the pid of the REPL process you are in when making the call.

    You can simply add the gen_server pid as a parameter to test:add, since you get it from test:start().