[erlang-questions] help with gen_fsm for a new erlang user

Greg Smyth gsmyth@REDACTED
Mon Aug 17 17:23:55 CEST 2009


Thanks Torben!

I ended up trying it in a slightly different way (using the 'timeout' event
for the run state as well, rather than explicitly using the timeout module)
- but your explanation helped me to see the mistakes in my thinking (how i
needed an explicit event to drive into the run state).

Cheers,
Greg

On Mon, Aug 17, 2009 at 3:10 PM, Torben Hoffmann <
torben.lehoff@REDACTED> wrote:

> Hi Greg,
>
> You have run into one of the small beauties of gen_fsm which can be a bit
> confusing when starting out with the state machines in Erlang.
>
> Your problem is that there is nothing driving your gen_fsm forward except
> for the initial timeout.
>
> In run you are waiting for an arbitrary event, but you never generate an
> event that will trigger the code.
>
> Speaking in terms of other state machine formalisms you are expecting an
> entry action to be executed when you enter a state, but there is no such
> thing out of the box for a gen_fsm.
>
> Given your requirements I might go as far as to suggest using a gen_server,
> but regardless you need to have something that drives your process.
>
> Suppose you create an API function for your existing code:
> run_stuff() ->
> gen_fsm:send_event(?MODULE,run_it).
>
> Then you add the following to run state:
> run(run_it,State) ->
> ... your old code
>
> This will allow you to call runner_fsm:run_stuff() from the command line
> and see some action.
>
> Doing this ever so often requires usage of functions from the timer module
> which I encourage you to investigate.
>
> You can use the timer module functions to call a function at your required
> rate inside or outside your gen_fsm.
>
> Hope this helps,
> Torben
>
>
>
> On Mon, Aug 17, 2009 at 15:22, Greg Smyth <gsmyth@REDACTED> wrote:
>
>> Hi all,
>>
>> I'm learning erlang/OTP and I'm trying to write a pretty simple gen_fsm
>> service, but i'm having a bit of trouble and was wondering if someone
>> could
>> help correct my mistakes:-
>>
>> The service should have 2 states:-
>>
>> 1) waiting - where it will be waiting on a specified timeout.
>> 2) running - where it will be running a function over a list of hosts
>> (specified in 'Hostlist' dictionary with the host as the key)
>>
>> The code i have compiles ok, and returns {ok, Pid} from start_link/1 - but
>> i
>> see none of my io:format messages ever appear...
>>
>> Here's the code:-
>>
>> %%%%%%%%%
>>
>> -module(runner_fsm).
>> -behaviour(gen_fsm).
>>
>> %% API
>> -export([start_link/1]).
>>
>> %% gen_fsm callbacks
>> -export([init/1, wait/2, run/2, wait/3, run/3, handle_event/3,
>>         handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).
>>
>> %% internals
>> -export([pinger/1]).
>>
>> -define(SERVER, ?MODULE).
>>
>> start_link(Hostlist) ->
>>  gen_fsm:start_link({local, ?SERVER}, ?MODULE, Hostlist, []).
>>
>> init(Hostlist) ->
>>  {ok, wait, Hostlist, 30000}.
>>
>> wait(timeout, State) ->
>>  {next_state, run, State}.
>>
>> run(_Event, State) ->
>>  Hosts = dict:fetch_keys(State),
>>  case lists:foreach(fun(Elem) -> runner_fsm:pinger(Elem) end, Hosts) of
>>    ok ->
>>      doNothingforNow;
>>    fail ->
>>      doNothingforNow
>>  end,
>>  {next_state, wait, State, 30000}.
>>
>> wait(_Event, _From, State) ->
>>  Reply = ok,
>>  {reply, Reply, wait, State, 30000}.
>>
>> run(_Event, _From, State) ->
>>  Reply = ok,
>>  {reply, Reply, run, State}.
>>
>> handle_event(_Event, StateName, State) ->
>>  {next_state, StateName, State}.
>>
>> handle_sync_event(Event, From, StateName, State) ->
>>  Reply = ok,
>>  {reply, Reply, StateName, State}.
>>
>> handle_info(_Info, StateName, State) ->
>>  {next_state, StateName, State}.
>>
>> terminate(_Reason, _StateName, _State) ->
>>  ok.
>>
>> code_change(_OldVsn, StateName, State, _Extra) ->
>>  {ok, StateName, State}.
>>
>> pinger(Host) ->
>>  Command = lists:concat(["ping -c 1 ", Host, "; echo $?"]),
>>  ExitCode = lists:last(string:tokens(os:cmd(Command), "\n")),
>>  case ExitCode of
>>    "0" -> io:format("OK: ~p~n", [Host]),
>>           ok;
>>     _  -> io:format("BAD: ~p~n", [Host]),
>>           fail
>>  end.
>>
>> %%%%%%%%%%%
>>
>> Any ideas/hints as to what i'm doing wrong?
>>
>> Many thanks,
>> Greg
>>
>
>
>
> --
> http://www.linkedin.com/in/torbenhoffmann
>


More information about the erlang-questions mailing list