In Process module, I haven't found function like erlang's function such as timer:send_interval. Does it exist or I have to call :timer:send_interval?
In Process module, I haven't found function like erlang's function such as timer:send_interval. Does it exist or I have to call :timer:send_interval?
:timer.send_interval/2 is prone to the message box overloading if the handler takes more time to process than the interval. That’s why in elixir we use the following approach with Process.send_after/4.
defmodule MyMod do
use GenServer
@impl GenServer
def init(state) do
state =
state
|> Map.put_new(:interval, 5_000)
|> Map.put_new(:schedule, nil)
# optional; to be called if the first message
# from outside expects the periodic
# function to be called at least once
# {:noreply, state} = handle_info(:work, state)
{:ok, state}
end
@impl GenServer
def handle_info(:work, state) do
# process periodic event
# optional; to allow calling it from outside without
# setting many subsequent timers
# if is_reference(state.schedule),
# do: Process.cancel_timer(state.schedule)
{:noreply, Map.put(state, :schedule, schedule_work(state.interval))}
end
@spec schedule_work(interval :: non_neg_integer()) :: :error | reference()
defp schedule_work(interval) when is_integer(interval) and interval > 0,
do: Process.send_after(self(), :work, interval)
This approach guarantees that the interval would last between the time when the previous message has been handled and the new message.
Sidenote: to call erlang functions from elixir, one uses the same dot notation as calling domestic functions (module[dot]function), e. g.: :timer.send_interval not :timer:send_interval.