[erlang-questions] Order of message processing by a gen_server
Andreas Hillqvist
andreas.hillqvist@REDACTED
Thu Dec 6 09:09:05 CET 2007
You could model this using an gen_fsm:
-module(new_file).
-define(NAME, ?MODULE).
-behaviour(gen_fsm).
%% External exports
-export([start_link/0,
send_cancel/0]).
%% gen_fsm exports
-export([init/1,
phase1/2,
phase1/3,
phase2/2,
phase2/3,
phase3/2,
phase3/3,
handle_event/3,
handle_sync_event/4,
handle_info/3,
terminate/3,
code_change/4]).
-record(state, {}).
%% External functions
start_link() ->
Args = [],
Options = [],
{ok, Pid} = gen_fsm:start_link({local, ?NAME}, ?MODULE, Args, Options).
send_cancel() ->
gen_fsm:send_all_state_event(?NAME, cancel).
send_phase1() ->
gen_fsm:send_event(?NAME, phase1).
send_phase2() ->
gen_fsm:send_event(?NAME, phase2).
send_phase3() ->
gen_fsm:send_event(?NAME, phase3).
%% gen_fsm callbacks
init([]) ->
send_phase1(),
{ok, phase1, #state{}}.
phase1(phase1, StateData) ->
do_phase_1(),
send_phase2(),
{next_state, phase2, StateData};
phase1(_, StateData) ->
{next_state, phase1, StateData}.
phase1(_, From, StateData) ->
Reply = ok,
{reply, Reply, phase1, StateData}.
phase2(phase2, StateData) ->
do_phase_2(),
send_phase3(),
{next_state, phase3, StateData};
phase2(_, StateData) ->
{next_state, phase2, StateData}.
phase2(_, From, StateData) ->
Reply = ok,
{reply, Reply, phase2, StateData}.
phase3(phase3, StateData) ->
do_phase_3(),
io:format("Finished, so no I will stop!\n"),
Reason = normal,
{stop, Reason, StateData};
phase3(_, StateData) ->
{next_state, phase3, StateData}.
phase3(_, From, StateData) ->
Reply = ok,
{reply, Reply, phase3, StateData}.
handle_event(cancel, StateName, StateData) ->
io:format(" - We have recived cancel in ~p -!\n"
" - We now stop! -\n", [StateName]),
Reason = canceled,
{stop, Reason, StateData};
handle_event(_, StateName, StateData) ->
{next_state, StateName, StateData}.
handle_sync_event(Event, From, StateName, StateData) ->
Reply = ok,
{reply, Reply, StateName, StateData}.
handle_info(Info, StateName, StateData) ->
{next_state, StateName, StateData}.
terminate(Reason, StateName, StatData) ->
ok.
code_change(OldVsn, StateName, StateData, Extra) ->
{ok, StateName, StateData}.
do_phase_1() ->
io:format("Begin phase_1\n"),
timer:sleep(5000),
io:format("End phase_1\n").
do_phase_2() ->
io:format("Begin phase_2\n"),
timer:sleep(5000),
io:format("End phase_2\n").
do_phase_3() ->
io:format("Begin phase_3\n"),
timer:sleep(5000),
io:format("End phase_3\n").
How are job handled?
Can more than one job run at once: Is one process/gen_server/gen_fsm
created when a job is run and ended when it is finished?
Or is there only one a job that can be run at a time: A static
process/gen_server/gen_fsm with an ideal state that recives the jobs?
Kind regards,
Andreas Hillqvist
2007/12/6, Jack Orenstein <jao@REDACTED>:
> Thanks again for your responses and code samples.
>
> You asked:
>
> > Example:
> > 1. phase1 is sent to my_fms
> > 2. my_fms receives phase1
> > 3. my_fms starts processing phase1
> > 4. phase2 is sent to my_fms
> > 5. phase3 is sent to my_fms
> > 6. cancel is sent to my_fms
> > 7. my_fms finish processing phase1
> > 8. my_fms receives phase2
> > 9. my_fms starts processing phase2
> > 10. my_fms finish processing phase2
> > 11. my_fms receives phase3
> > 12. my_fms starts processing phase3
> > 13. my_fms finish processing phase3
> > 14. my_fms receives cancel
> >
> > As I intrepid it, you want step 8 to receive cancel event and ignore
> > the transitions to phase2 and phase3?
>
> It depends what you mean by "my_fms receives ...". At a high level,
> what I want to do is to process these phases in order, and stop
> processing them when a cancel message arrives. If my_fms has a cancel
> message in it, then I definitely want that message to be processed
> next by the receive.
>
> I think the problem can be simplified by having each phase trigger the
> next one, e.g.
>
> loop() ->
> receive
> cancel -> cancelled;
> phase1 -> do_phase_1(), self() ! phase2, loop();
> phase2 -> do_phase_2(), self() ! phase3, loop();
> phase3 -> do_phase_3(), ok
> end.
>
> Then I can start the phases:
>
> P = spawn(fun() -> loop() end),
> P ! phase1
>
> and cancel anytime:
>
> P ! cancel
>
> I think this could be translated into gen_server code, using
> handle_cast instead of handle_call.
>
> By the way, you mentioned that following a cancel, the message queue
> should be emptied, which makes sense. How is that done?
>
> Jack
>
>
More information about the erlang-questions
mailing list