[erlang-questions] Best practices in gen_fsm usage

Vance Shipley vances@REDACTED
Tue Dec 13 10:33:56 CET 2011


On Tue, Dec 13, 2011 at 12:38:51AM -0800, Steve Davis wrote:
}  I need to figure out why I end up with a gen_server after starting
}  out with a gen_fsm, and then may have something more fruitful to say.

One good reason to migrate a gen_fsm to gen_server is that it becomes
clear that it has no unique states.  In my experience it is much more
common to migrate a gen_server to a gen_fsm as it becomes clear that
there are unique states.  The following provides a contrived example.

Start with a gen_server:

     -module(foo_server).
     -export([init/1, handle_call/3]).
     -behaviour(gen_server).

     -record(state, {sap}).
     
     init(_Args) ->
          {ok, #state{}}.
     
     handle_call(bind, From, State) ->
          SAP = bind(),
          {reply, ok, State#state{sap = SAP}};
     handle_call(get, From, #state{sap = SAP} = State) ->
          Got = get(SAP),
          {reply, Got, State}.


Later realize that binding may take time and have varying results:

     -module(foo_fsm).
     -export([init/1, idle/3, binding/2, bound/3]).
     -behaviour(gen_fsm).
     
     -record(statedata, {sap, from}).

     init(_Args) ->
          {ok, idle, #statedata{}}.
     
     idle(bind, From, Statedata) ->
          bind(),
          {next_state, binding, Statedata#statedata{from = From}}.
     
     binding({error, Reason}, #statedata{from = From} = Statedata) ->
          gen_fsm:reply(From, {error, Reason}),
          {next_state, idle, #statedata{}};
     binding(SAP, #statedata{from = From} = Statedata) ->
          gen_fsm:reply(From, ok),
          {next_state, bound, Statedata#statedata{sap = SAP}}.
     
     bound(get, From, #statedata{sap = SAP} = Statedata) ->
          Got = get(SAP),
          {reply, Got, bound, Statedata}.


-- 
     -Vance



More information about the erlang-questions mailing list