I have a question on gen_fsm timeout. Let's say you have a set of gen_fsm with two states (in future can be more): idle
which is the starting state and working
.
Any 5 seconds the gen_fsm will check a particular parameter and according to it will remain in idle
or will move to working
. Whenever a gen_fsm will move to working
, it will send a message (using gen_fsm:send_all_state_event/2
) to all the other gen_fsm: the ones in idle
should move to working
while the one in working
should not care about the incoming message.
Now, the point is that I don't want to have a skew in the states timeout (e.g. what happens if the machine is in working
for 3 seconds and receives a message? A 5 seconds timeout is no more valid, since I want to preserve a fixed timeout no matter what (this means that a timeout message should be triggered at fixed times).
Here are the salient parts of my solution, which uses now()
and time:now_diff/2
. I have a small drift anyhow, but seems fair since talking about fractions of seconds.
Do you think it is valid?
{ok, idle, #state{time = now()}, 5000}.
idle(timeout, State) ->
%% do some operations
{next_state, idle, State#state{time = now()}, 5000}.
working(timeout, State) ->
%% do some other actions
{next_state, working, State#state{time = now()}, 5000}.
handle_event(work, working, #state{time = Time} = State) ->
Timeout = round(timer:now_diff(now(), Time) / 1000),
{next_state, working, State, Timeout}.
handle_event(work, StateName, state{time = Time} = State) ->
Timeout = round(timer:now_diff(now(), Time) / 1000),
{next_state, working, State, Timeout}.
You can use either timer:apply_interval to call a api function that sends the event to your fsm.
Or you use timer:send_interval to send a custom message that you can handle in the handle_info callback in your gen_fsm.