在处理状态超时的同时优雅地退出gen_statem

时间:2018-08-08 14:35:35

标签: erlang otp

如何在gen_statem中从state_timeout正常退出?通常,对于gen_statem,我可以从状态函数返回“ stop”或{stop,Reason},statem将终止。但是,如果我使用状态超时方法,则从init返回:

  

{确定,州名,州,{州超时,2000,超时}}

在2000年之后调用handle_event(state_timeout,timeout,StateName,State)方法。从此返回“ stop”会产生错误……:

代码:

  

handle_event(状态超时,超时,状态名称,状态)->
  lager:warning(“设备超时:状态中的〜p:〜p”,   [State#state.uuid,StateName]),
  {stop,timeout};

错误:

  

14:29:56.992 [警告] <0.916.0> handle_event(299):超时   设备:状态未定义:init_auth 14:29:56.992 [错误] <0.767.0>   未定义(未定义):已退出大型事件处理程序error_logger_lager_h   原因为{'EXIT',{{badmatch,[module,{state_timeout,timeout

我可以从该函数返回什么以正常退出?能用state_timeout完成吗?如果这是一个明显的问题,请指出正确的方向。这里的文档:http://erlang.org/doc/man/gen_statem.html#type-transition_option似乎没有提到state_timeout的任何返回。似乎我可以指定“下一个状态”,但是退出似乎没有定义

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

系统生成错误,因为与停止消息相关的原因不是// Point(specify location of x, specify location of y) // with object initializer var frmUsers = new FrmUsers { StartPosition = FormStartPosition.Manual, Location = new Point(0, 0) }; // or var frmUsers = new FrmUsers(); frmUsers.StartPosition = FormStartPosition.Manual; frmUsers.Location = new Point(0, 0);

在这个小例子中,状态机在达到20个超时条件后“正常”退出:

normal

在作品中:

-module (statem).

-behaviour(gen_statem).

-export ([start_link/0]).
-export([init/1, callback_mode/0, terminate/3, code_change/4,handle_event/4]).

start_link() ->
    gen_statem:start_link({local,?MODULE}, ?MODULE, [], []).

init([]) ->
    {ok, state1, #{info => 0, call => 0 , cast => 0, timeout => 0},[{timeout, 2000, timeout_event}]}.


callback_mode() ->
    handle_event_function.

handle_event(timeout,_EventContent,_State,#{timeout := 20}) ->
    io:format("max timeout count reached~n"),
    {stop, normal};
handle_event(EventType,EventContent,State,Data) ->
    io:format("EtventType : ~p~nEventContent : ~p~nState : ~p~nData : ~p~n", [EventType,EventContent,State,Data]),
    NewData = process_event(EventType,EventContent,State,Data),
    {next_state, State, NewData,[{timeout, 2000, timeout_event}]}.

terminate(_Reason, _State, _Data) ->
    ok.

code_change(_Vsn, State, Data, _Extra) ->
    {ok, State, Data}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

process_event(info,_EventContent,_State,Data) ->
    maps:update(info, maps:get(info, Data)+1, Data);
process_event(cast,_EventContent,_State,Data) ->
    maps:update(cast, maps:get(cast, Data)+1, Data);
process_event(timeout,_EventContent,_State,Data) ->
    maps:update(timeout, maps:get(timeout, Data)+1, Data);
process_event({call,From},EventContent,_State,Data) ->
    gen_statem:reply(From, {got,EventContent}),
    maps:update(call, maps:get(call, Data)+1, Data).

{EDIT]

它与state_timeout语法的工作原理相同(我并没有花太多时间去理解它们的区别)

您的代码段中存在语法错误,操作必须包含在列表中(即使只有一个操作)。我尝试了此修改后的代码,它可以正常工作:

74> c(statem).                     
{ok,statem}
75> {ok,Pid} = statem:start_link().
{ok,<0.197.0>}
EtventType : timeout               
EventContent : timeout_event
State : state1
Data : #{call => 0,cast => 0,info => 0,timeout => 0}
EtventType : timeout              
EventContent : timeout_event
State : state1
Data : #{call => 0,cast => 0,info => 0,timeout => 1}
76> Pid ! hello.                  
EtventType : info
EventContent : hello
State : state1
Data : #{call => 0,cast => 0,info => 0,timeout => 2}
hello
EtventType : timeout               
EventContent : timeout_event
State : state1
Data : #{call => 0,cast => 0,info => 1,timeout => 2}
EtventType : timeout              
EventContent : timeout_event
State : state1
Data : #{call => 0,cast => 0,info => 1,timeout => 3}
77> gen_statem:cast(Pid,cast_msg).
EtventType : cast
EventContent : cast_msg
State : state1
Data : #{call => 0,cast => 0,info => 1,timeout => 4}
ok
...
80> gen_statem:call(Pid,call_msg).
EtventType : {call,{<0.190.0>,#Ref<0.571135265.1570766849.45359>}}
EventContent : call_msg
State : state1
Data : #{call => 0,cast => 3,info => 1,timeout => 17}
{got,call_msg}
EtventType : timeout
EventContent : timeout_event
State : state1
Data : #{call => 1,cast => 3,info => 1,timeout => 17}
...
EtventType : timeout              
EventContent : timeout_event
State : state1
Data : #{call => 2,cast => 4,info => 1,timeout => 19}
max timeout count reached
84>