如何使用 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