[erlang-questions] Generic server and selective receives

Vance Shipley vances@REDACTED
Mon Feb 17 06:15:08 CET 2014


On Mon, Feb 17, 2014 at 12:55:19AM +0100, ludovic@REDACTED wrote:
}  Now, I would like to implement this as a gen_server. But I don't know
}  how. The Idea is to timeout quickly if no message of the expected
}  clauses-set comes.
}  
}  * I thought of a gen_fsm but it will crash if it's sent a message when
}  in the "no client" state, right ? (Plus i may want to handle more
}  receive clauses in the "no client" part)

In the example below it will crash if anything but a '{set_client, Pid}'
event is received during the 'wait_for_client' state but until you define
what it should do that is fine.  If it should handle additional events
add clauses to wait_for_client/2.

}  * I thougt about time calculations but it's seems too complicated for
}  no reason ; I prefer use the simple gen_* timeouts.

It's not.

}  * I could keep my current implementation and adapt the module to fit
}  in a supervision tree but I believe I willll miss common OTP features.

Unless you reimplement most of gen.erl you certainly will.


-module(mbox_fsm).

-behaviour(gen_fsm).

-export([init/1, handle_event/3, handle_sync_event/4, handle_info/3,
         terminate/3, code_change/4]).
-export([wait_for_client/2, wait_for_request/2]).

-define(MAXTIME, 60000).

-record(statedata, {client_pid, mailbox = [], timeout}).

init(_Arg) ->
	process_flag(trap_exit, true),
	{ok, wait_for_client, #statedata{}, 10000}.

wait_for_client({set_client, Pid}, StateData) ->
	NextStateData = StateData#statedata{client_pid = Pid},
	{next_state, wait_for_request, NextStateData, ?MAXTIME}.

wait_for_request({set_client, Pid},
			#statedata{timeout = Then} = StateData) ->
	NextTimeout = ?MAXTIME - timer:now_diff(os:timestamp(), Then),
	NextStateData = StateData#statedata{client_pid = Pid,
			timeout = NextTimeout},
	{next_state, wait_for_request, NextStateData, NextTimeout};
wait_for_request({message, M},
		StateData#statedata{mailbox = Mailbox, timeout = Then}) ->
	NextTimeout = ?MAXTIME - timer:now_diff(os:timestamp(), Then),
	NextStateData = StateData#statedata{{mailbox = [M | Mailbox]},
	{next_state, wait_for_request, NextStateData, NextTimeout};
% A handful of other clauses
wait_for_request(timeout, StateData) ->
	{stop, timeout, StateData}.

handle_info(Info, _StateName, StateData) ->
	{stop, Info, StateData}.

terminate(_Reason, _StateName, _StateData) ->
	ok.

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

-- 
	-Vance



More information about the erlang-questions mailing list