【问题标题】:Erlang: observe gen_server state without disturbing timeoutErlang:在不干扰超时的情况下观察 gen_server 状态
【发布时间】:2016-01-25 06:40:08
【问题描述】:

我有一个模仿 gen_fsm 的 gen_server,(不要问我为什么...),如果没有调用 gen_server:callgen_server:call 将导致这个 gen_server 从当前状态转移到下一个状态某个时间,gen_server 终止。

更具体地说,gen_server 的生命周期如下所示:

state_1 -> state_2 -> ... -> state_N -> terminated

当服务器处于 state_i 时,如果在此服务器上没有调用 gen_server 调用,则在 t_i 秒后,服务器将进入状态终止,这是通过使用 {reply, Reply, NewState, t_i} 作为 @ 的返回来实现的987654325@.

该方法的问题是,我无法从这个 gen_server 中检索一些信息,为此,我需要对其调用 gen_server:call,这会搞砸超时。

一种可能的解决方法是将最后一个状态转移时间戳放入状态,在每次检索调用后,将新的超时重置为适当的值,原型如下所示:

handle_call(get_a, _From, #state{a = 1,
                                 state = state_2,

                                 %% this is the timestamp when the server transfered to state_2
                                 unixtime = T1

                                }=S) ->
    Reply = S#state.a,
    NewTimeout = t_2 - (current_unixtime() - T1),
    {reply, Reply, S, NewTimeout};

这样可以得到我想要的效果,但是很丑,有没有更好的办法呢?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    如果您想独立于呼叫等其他事件设置超时,最好使用定时消息。

    当你设置超时使用 erlang:send_after/3:

    TimerRef = erlang:send_after(10000, self(), my_timeout).
    

    您可以随时使用 erlang:cancel_timer/1 取消超时。

    erlang:cancel_timer(TimerRef).
    

    用handle_info接收它:

     handle_info(my_timeout, State) ->
    

    如果您需要多个此类超时,请使用不同的消息,或者如果您可能存在某种竞争条件并需要进一步控制,您可以使用 erlang:make_ref/0 创建唯一引用并发送类似 {Ref , my_timeout}。

    注意边缘情况 - 请记住,您可以取消计时器,然后仍然意外收到它(因为当您取消时它在您的消息队列中),并且您不会使它们独一无二(如上面使用参考建议的那样)您可能会期待超时,并尽早获得它,因为它是进入您的消息队列等的前一个(与参考一样,您可以检查它是最新的集合)。这些事情很容易处理,但要小心。

    【讨论】:

      猜你喜欢
      • 2014-05-12
      • 1970-01-01
      • 1970-01-01
      • 2010-12-09
      • 1970-01-01
      • 1970-01-01
      • 2015-02-25
      • 1970-01-01
      • 2016-04-19
      相关资源
      最近更新 更多