I have erlang gen_fsm, my first state:
begin({Nick}, _From, State) ->
{reply, true, next_state, State}.
Then i have:
next_state(_Event, _From, State) ->
io:format("Test \n"),
{reply, ok, begin, State}.
But i don't seen Test note in shell
How correctly transit to a new state?
First of all, ensure that begin is the actual initial state of your FSM. You specify the initial state of your FSM by returning, in your init function, something like:
{ok, begin, State}
Where begin is your initial state.
Also, note that you're defining a Module:StateName/3 function, which will be called any time a gen_fsm:sync_send_event is performed on your FSM. If you're trying to send events to the FSM using gen_fsm:send_event, you should instead define a function Module:StateName/2, which is its asynchronous version.
Finally, try to debug your modules by tracing them, rather than adding printouts. It's much simpler and it avoids you recompiling your code time after time.
More information are avilable here.
you may find some examples here:
http://spawnlink.com/articles/an-introduction-to-gen_fsm-erlybanks-atm/index.html
and here:
http://pdincau.wordpress.com/2010/09/07/an-introduction-to-gen_fsm-behaviour/
Hope it helps
Related
Suppose I have a gen_server:
-module(myserver).
-behavior(gen_server).
-export([init/1, handle_call/3]).
init(Arg) -> % ...
handle_call(Request, From, State) -> % ...
Compiling this naturally produces a warning:
myserver.erl:2: Warning: undefined callback function handle_cast/2 (behaviour 'gen_server')
How do I deal with this warning if I my server isn't going to need handle_cast/2? Do I define a placeholder function just to satisfy the compiler? For example:
handle_cast(_Request, _State) -> unimplemented.
Or do I ignore/suppress the warning message?
What is the proper way to write a gen_server where not all callback functions will be used?
We should NOT ignore the warning message, this makes us difficult to trace errors/bugs in our application in future. Leaving the placeholder function is a better way, but it's should like below:
handle_cast(_Msg, State) ->
{noreply, State}.
By default, this function can't data to the caller, so you can avoid to crash your application when you or your colleagues use gen_sever:cast/2.
I didn't have specific way to write gen_sever. In a big project that I worked for, they just leave the placeholder like below to use in the future. They don't care much about callback functions is used or not. We should take care about normal function is used or not rather than callback functions.
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
How do I deal with this warning if I my server isn't going to need
handle_cast/2?
Then your server isn't a gen_server, so you can remove the line:
-behavior(gen_server).
which is what causes the compiler to check that the gen_server callback functions are present.
The bottom line is that OTP requires a contract between your code and the OTP behaviors. If you don't want to adhere to the contract, then you can't use OTP behaviors. In other words, you are required to implement ALL the callback functions.
Is it recommended to add logging to the supposedly unused callback
function so that their inadvertent use would appear in the logs?
It's up to you. It sounds like a good idea to me.
Is it possible to inspect the internal state of a gen_server after a callback function has been called? I would rather not change the API of my server here.
You could use sys:get_state/1 which works nicely with all gen's.
Maybe, you would found useful another approach to unit-testing gen_servers.
Instead of running gen_server process and testing its behaviour, you can directly test gen_server callbacks and then inspect its state transitions.
For example:
-module(foo_server).
%% Some code skipped
handle_call({do_stuf, Arg}, _From, State) ->
NewState = modify_state(
{reply, {stuf_done, Arg}, NewState}.
%% Some code skipped
-ifdef(TEST)
do_stuf_test_() ->
{setup,
fun() ->
{ok, InitState} = foo_server:init(SomeInitParams),
InitState
end,
fun(State) ->
ok = foo_server:terminate(shutdown, State)
end,
fun(State) ->
Result = foo_server:handle_call({do_stuf, hello}, undefined, State),
[
?_assertMatch({reply, {stuf_done, hello}, _}, Result)
]
end
}
}.
-endif.
See discussion of this approach here
Also, if you dealing with realy complex states and state transitions, maybe you would be found proper helpful.
Consider I have a FSM implemented with gen_fsm. For a some Event in a some StateName I should write data to database and reply to user the result. So the following StateName is represented by a function:
statename(Event, _From, StateData) when Event=save_data->
case my_db_module:write(StateData#state.data) of
ok -> {stop, normal, ok, StateData};
_ -> {reply, database_error, statename, StateData)
end.
where my_db_module:write is a part of non-functional code implementing actual database write.
I see two major problems with this code: the first, a pure functional concept of FSM is mixed by part of non-functional code, this also makes unit testing of FSM impossible. Second, a module implementing a FSM have dependency on particular implementation of my_db_module.
In my opinion, two solutions are possible:
Implement my_db_module:write_async as sending an asynchronous message to some process handling database, do not reply in statename, save From in StateData, switch to wait_for_db_answer and wait result from db management process as a message in a handle_info.
statename(Event, From, StateData) when Event=save_data->
my_db_module:write_async(StateData#state.data),
NewStateData=StateData#state{from=From},
{next_state,wait_for_db_answer,NewStateData}
handle_info({db, Result}, wait_for_db_answer, StateData) ->
case Result of
ok -> gen_fsm:reply(State#state.from, ok),
{stop, normal, ok, State};
_ -> gen_fsm:reply(State#state.from, database_error),
{reply, database_error, statename, StateData)
end.
Advantages of such implementation is possibility to send arbitrary messages from eunit modules without touching actual database. The solution suffers from possible race conditions, if db reply earlier, that FSM changes state or another process send save_data to FSM.
Use a callback function, written during init/1 in StateData:
init([Callback]) ->
{ok, statename, #state{callback=Callback}}.
statename(Event, _From, StateData) when Event=save_data->
case StateData#state.callback(StateData#state.data) of
ok -> {stop, normal, ok, StateData};
_ -> {reply, database_error, statename, StateData)
end.
This solution doesn't suffer from race conditions, but if FSM uses many callbacks it really overwhelms the code. Although changing to actual function callback makes unit testing possible it doesn't solves the problem of functional code separation.
I am not comfortable with all of this solutions. Is there some recipe to handle this problem in a pure OTP/Erlang way? Of may be it is my problem of understating principles of OTP and eunit.
One way to solve this is via Dependency Injection of the database module.
You define your state record as
-record(state, { ..., db_mod }).
And now you can inject db_mod upon init/1 of the gen_server:
init([]) ->
{ok, DBMod} = application:get_env(my_app, db_mod),
...
{ok, #state { ..., db_mod = DBMod }}.
So when we have your code:
statename(save_data, _From,
#state { db_mod = DBMod, data = Data } = StateData) ->
case DBMod:write(Data) of
ok -> {stop, normal, ok, StateData};
_ -> {reply, database_error, statename, StateData)
end.
we have the ability to override the database module when testing with another module. Injecting a stub is now pretty easy and you can thus change the database code representation as you see fit.
Another alternative is to use a tool like meck to mock the database module when you are testing, but I usually prefer making it configurable.
In general though, I tend to split the code which is complex into its own module so it can be tested separately. I rarely do much unit testing of other modules and prefer large-scale integration tests to handle errors in such parts. Take a look at Common Test, PropEr, Triq and Erlang QuickCheck (The latter is not open source, nor is the full version free).
Is it possible to obtain the current state of a gen_server process (presumably by sending some system message)? It could be useful when debugging.
Of course, I can add a message which returns the current state to handle_call:
get_state(Server) -> gen_server:call(Server, '$get_state').
%% in every gen_server I want to debug
...
handle_call('$get_state', _From, State) ->
{reply, State, State};
...
but is there something built-in (even if it is a bit hacky)?
Use sys:get_status/1,2 function. It's definition is:
get_status(Name,Timeout) ->
{status, Pid, {module, Mod}, [PDict, SysState, Parent, Dbg, Misc]}
SysState will contain state of the process. It works for all processes using OTP behaviors and other processes implementing proc_lib and sys requirements.
There is actually a function that returns the state directly: sys:get_state/1,2. It accepts pid or name of the process and can optionally be given a timeout.
I have a process that needs to do some work every fifteen seconds. I'm currently doing it like this:
-behavior(gen_server).
interval_milliseconds ()-> 15000.
init()->
{ok,
_State = FascinatingStateData,
_TimeoutInterval = interval_milliseconds ()
}.
%% This gets called automatically as a result of our handlers
%% including the optional _TimeoutInterval value in the returned
%% Result
handle_info(timeout, StateData)->
{noreply,
_State = do_some_work(StateData),
_TimeoutInterval = interval_milliseconds ()
}.
This works, but it's extremely brittle: if I want to teach my server a new message, when I write any new handler function, I have to remember to include the optional timeout interval in its return value. That is, say if I'm handling a synchronous call, I need to do this:
%% Someone wants to know our state; tell them
handle_call(query_state_data, _From, StateData)->
{reply, StateData, _NewStateData = whatever (), interval_milliseconds ()};
instead of
%% Someone wants to know our state; tell them
handle_call(query_state_data, _From, StateData)->
{reply, StateData, _NewStateData = whatever ()};
As you might guess, I've made that very mistake a number of times. It's nasty, because once the code handles that query_state_data message, the timeouts no longer get generated, and the whole server grinds to a halt. (I can "defibrillate" it manually by getting a shell on the machine and sending a "timeout" message by hand, but ... eww.)
Now, I could try to remember to always specify that optional Timeout parameter in my Result value. But that doesn't scale: I'll forget someday, and will be staring at this bug once again. So: what's a better way?
I don't think I want to write an actual loop that runs forever, and spends most of its time sleeping; that seems counter to the spirit of OTP.
Use timer:send_interval/2. E.g.:
-behavior(gen_server).
interval_milliseconds()-> 15000.
init()->
timer:send_interval(interval_milliseconds(), interval),
{ok, FascinatingStateData}.
%% this clause will be called every 15 seconds
handle_info(interval, StateData)->
State2 = do_some_work(StateData)
{noreply, State2}.
The best way is:
init([]) ->
Timer = erlang:send_after(1, self(), check),
{ok, Timer}.
handle_info(check, OldTimer) ->
erlang:cancel_timer(OldTimer),
do_task(),
Timer = erlang:send_after(1000, self(), check),
{noreply, Timer}.
Use the timer module :)