As stated, :gen_statem
has a concept of event timeouts, where the timeout will be automatically cancelled if an event is received before the timeout expires. You create an event timeout by returning an “event timeout” action from a callback
{state, data, [:timer.seconds(5)]}
# or
{state, data, [{:timeout, :timer.seconds(5), value_to_include_in_callback}]}
Alternatively, if you want control over when the timeout is cancelled, you can use a generic timeout. As long as you keep returning the same generic timeout name from callbacks, then the timeout will keep being reset (or you can explicitly cancel it), otherwise the timeout expires and the process will receive a message about it.
{state, data, [{{:timeout, :my_name}, :timer.seconds(5), value_to_include}]}
GenServer also has builtin timeout support that can be used to detect inactivity:
def handle_info(:timeout, state) do
dbg("5 seconds of inactivity have elapsed")
{:noreply, state}
end
def handle_info(_, state) do
{:noreply, state, :timer.seconds(5)}
end
And, if you want to be in control over when the timeout is cancelled, you can do so with Process.send_after/4 and Process.cancel_timer/2:
def handle_info(:timeout, state) do
dbg("5 seconds of inactivity have elapsed")
{:noreply, state}
end
def handle_info(_, state) do
if state.timer, do: Process.cancel_timer(state.timer)
state = put_in(state.timer, Process.send_after(self(), :timeout, :timer.seconds(5)))
{:noreply, state}
end