如何使用 Elixir 创建周期性定时器?
How to create periodical timer with Elixir?
我正在尝试使用 Elixir 创建一个周期性计时器,它将周期长度(毫秒)作为参数和一个在时间结束后执行的函数。用户还应该可以选择取消计时器。如果传递函数 returns :cancel
值,那么它也应该取消定时器。这是我的代码:
def start_timer(period, callback_function) do
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
timer = Process.send_after(self(), :work, period)
{:ok, %{timer: timer}}
end
def handle_info(:work, period) do
IO.puts("This should printed after every period")
# Start the timer again
timer = Process.send_after(self(), :work, period)
{:noreply, %{timer: timer}}
end
我还没有实现cancel-feature或者参数函数的执行,因为上面的还不行。我应该怎么做?非常感谢任何建议。
您似乎没有在任何地方使用 callback_function
。如果您希望它在计时器的整个 运行 期间都可用,则需要在 GenServer.start_link/3
的第二个参数的状态中将其传递给 GenServer.start_link/3
,例如
GenServer.start_link(__MODULE__, %{callback_function: callback_function}, name: __MODULE__)
下面是一些周期性执行函数的代码:
defmodule Cronlike do
use GenServer
@allowed_units [:second, :minute, :hour, :day]
def start_link(state) do
GenServer.start_link(__MODULE__, state)
end
@impl true
def init(%{interval: interval, unit: unit} = state) when is_integer(interval) and interval > 0 and unit in @allowed_units do
# wait, bang:
Process.send_after(self(), :tick, to_ms(interval, unit))
# bang, wait:
# send(self(), :tick, to_ms(interval, unit))
{:ok, state}
end
@impl true
def handle_info(:tick, %{interval: interval, unit: unit,
callback_function: callback_function} = state) do
case callback_function.() do
:cancel -> send(self(), :quit)
_ -> nil
end
Process.send_after(self(), :tick, to_ms(interval, unit))
{:noreply, state}
end
def handle_info(:quit, state) do
{:stop, :normal, state}
end
defp to_ms(interval, :second), do: interval * 1000
defp to_ms(interval, :minute), do: to_ms(interval, :second) * 60
defp to_ms(interval, :hour), do: to_ms(interval, :minute) * 60
defp to_ms(interval, :day), do: to_ms(interval, :hour) * 24
end
本文改编自我写的一篇相关文章Wait, Bang vs. Bang, Wait: Subtleties in Elixir Cron Scripts
我正在尝试使用 Elixir 创建一个周期性计时器,它将周期长度(毫秒)作为参数和一个在时间结束后执行的函数。用户还应该可以选择取消计时器。如果传递函数 returns :cancel
值,那么它也应该取消定时器。这是我的代码:
def start_timer(period, callback_function) do
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
timer = Process.send_after(self(), :work, period)
{:ok, %{timer: timer}}
end
def handle_info(:work, period) do
IO.puts("This should printed after every period")
# Start the timer again
timer = Process.send_after(self(), :work, period)
{:noreply, %{timer: timer}}
end
我还没有实现cancel-feature或者参数函数的执行,因为上面的还不行。我应该怎么做?非常感谢任何建议。
您似乎没有在任何地方使用 callback_function
。如果您希望它在计时器的整个 运行 期间都可用,则需要在 GenServer.start_link/3
的第二个参数的状态中将其传递给 GenServer.start_link/3
,例如
GenServer.start_link(__MODULE__, %{callback_function: callback_function}, name: __MODULE__)
下面是一些周期性执行函数的代码:
defmodule Cronlike do
use GenServer
@allowed_units [:second, :minute, :hour, :day]
def start_link(state) do
GenServer.start_link(__MODULE__, state)
end
@impl true
def init(%{interval: interval, unit: unit} = state) when is_integer(interval) and interval > 0 and unit in @allowed_units do
# wait, bang:
Process.send_after(self(), :tick, to_ms(interval, unit))
# bang, wait:
# send(self(), :tick, to_ms(interval, unit))
{:ok, state}
end
@impl true
def handle_info(:tick, %{interval: interval, unit: unit,
callback_function: callback_function} = state) do
case callback_function.() do
:cancel -> send(self(), :quit)
_ -> nil
end
Process.send_after(self(), :tick, to_ms(interval, unit))
{:noreply, state}
end
def handle_info(:quit, state) do
{:stop, :normal, state}
end
defp to_ms(interval, :second), do: interval * 1000
defp to_ms(interval, :minute), do: to_ms(interval, :second) * 60
defp to_ms(interval, :hour), do: to_ms(interval, :minute) * 60
defp to_ms(interval, :day), do: to_ms(interval, :hour) * 24
end
本文改编自我写的一篇相关文章Wait, Bang vs. Bang, Wait: Subtleties in Elixir Cron Scripts