[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