読者です 読者をやめる 読者になる 読者になる

gen_fsm の Timeout について

まず @kuenishi, @kenji_rikitake, @itawasa, @cooldaemon にアドバイスを頂きました。本当にありがとうございます。

gen_fsm の Timeout は便利なんですが、結局状態が変わってしまうと無効になってしまうので独立したタイマーとしては使えません。

そこで gen_fsm:start_timer と gen_fsm:cancel_timer を使います。

そもそも需要が無いと思うので、わかる人向けに簡単に。

'SPAM'({timeout, Ref, Msg}, ...) ->
  ...
  {next_state, ...}.

'EGGS'({timeout, Ref, Msg}, ...) ->
  ...
  {next_state, ...}.

handle_event(...) ->
  TimerRef = StateData#state.timer_ref,
  case TimerRef of
    undefined ->
      ok;
    TRef ->
      gen_fsm:cancel_timer(TimerRef)
  end,
  NewTimerRef = gen_fsm:start_timer(Timeout, Msg),
  NewState = State#state{timer_ref = NewTimerRef},
  {next_state, 'SPAM', NewState};

つまるところこのイベントが呼ばれた場合はタイマーが毎回初期化されます。さらに状態がどうかわろうが、Timer 自体は独立して動いているので状態遷移による影響を受けません。

追記

@kuenishi からのコメントの通り gen_fsm:start_timer/2 って erlang:start_timer/3 のラッパーだったりするので、個人的には gen_server + erlang:start_timer で十分だったりしました。