R – How to do selective receives in gen_servers

erlang

I ported most of my app to OTP behaviors, but I'm stuck. I can't figure out how to do selective receives using a gen_server. If none of the callback function clauses match a message, rather than putting the message back in the mailbox, it errors out!

Now, everywhere I go, folks laud selective receives. Everywhere I go, folks laud OTP. Can it really be true that you can't have both at once? Doesn't this seem like a major, correctable shortcoming?

How do erlang programmers handle this?

EDIT (responding to zed's comment):

Here's an example where I'd like to see a list of integers printed in sorted order:

-module(sel_recv).
-behaviour(gen_server).

-export([start_link/0]).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
     terminate/2, code_change/3]).

-export([test/0]).

start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

test() ->
    gen_server:cast(?MODULE, test).

init([]) ->
    {ok, 0}.

handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

handle_cast(test, _State) ->
    lists:map(fun(N) ->
                      gen_server:cast(?MODULE, {result, N})
              end, [9,8,7,6,5,4,3,2,1]),
    {noreply, [1,2,4,5,6,7,8,9]};
handle_cast({result, N}, [N|R]) ->
    io:format("result: " ++ integer_to_list(N) ++ "~n"),
    {noreply, R}.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

Of course, in my real app, there are timer delays and the messages that need to be processed in order are interleaved with other messages. In particular, I send out http requests, sometimes many at once, sometimes one at a time with an interval between them. In any case, I need to collect them in order.

Best Answer

"plain_fsm" will allow you to do selective receive while still being OTP compliant.

http://github.com/esl/plain_fsm

Related Topic