【问题标题】:Gracefully exit from a gen_statem while processing a state timeout在处理状态超时时优雅地退出 gen_statem
【发布时间】:2019-01-15 21:01:43
【问题描述】:

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

{ok, StateName, State, {state_timeout, 2000, timeout}}

handle_event(state_timeout, timeout, StateName, State) 方法在 2000 年之后被调用。从这里返回“stop”会报错……:

代码:

handle_event(state_timeout, timeout, StateName, State) ->
lager:warning("设备超时: ~p in State: ~p", [State#state.uuid, StateName]),
{停止,超时};

错误:

14:29:56.992 [警告] handle_event(299): 超时 设备:未定义状态:init_auth 14:29:56.992 [错误] 未定义(未定义):Lager 事件处理程序 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 的任何返回。似乎我可以指定“下一个状态”,但似乎没有定义退出

感谢您的帮助!

【问题讨论】:

    标签: erlang erlang-otp


    【解决方案1】:

    系统生成错误,因为与停止消息相关的原因不是normal

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

    -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).
    

    工作中:

    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> 
    

    {编辑]

    它与语法 state_timeout 相同(我没有深入了解差异)

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

    -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},[{state_timeout, 2000, timeout}]}.
    
    
    callback_mode() ->
        handle_event_function.
    
    handle_event(state_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,[{state_timeout, 2000, timeout}]}.
    
    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(state_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).
    

    【讨论】:

    • 这是使用超时方法,而不是state_timeout。你知道为什么 state_timeout 方法不起作用吗?
    猜你喜欢
    • 2015-03-05
    • 2013-10-17
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 2017-02-18
    • 1970-01-01
    • 2011-11-26
    • 1970-01-01
    相关资源
    最近更新 更多