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

Torben Hoffmann torben.lehoff@REDACTED
Mon Aug 17 16:10:24 CEST 2009


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