【问题标题】:Which OTP behavior should I use for an "endless" repetition of tasks?我应该使用哪种 OTP 行为来“无休止地”重复任务?
【发布时间】:2015-08-14 15:15:18
【问题描述】:

我想在 Phoenix 应用程序旁边一遍又一遍地重复运行相同的操作序列(当然,如果工作人员出现问题,则不会导致整个 Web 应用程序崩溃)并且我真的不知道我是否应该使用GenServer、Elixir 的任务、代理或完全不同的东西,我到目前为止还没有想到。

当我启动我的 Phoenix 应用程序时,工作人员也应该启动,它会定期提取串行连接的一些值,通过 Phoenix 频道广播它们,收集它们直到达到 @save_interval,然后计算中位数,广播中位数通过不同的通道并将其写入 InfluxDB。现在我有这样的东西(有点工作):

def do_your_thing(serial_pid) do
  Stream.interval(@interval_live)
    |> get_new_values_from_serial(serial_pid)
    |> broadcast!("live-channel:#{@name}")
    |> Enum.take(div(@interval_save, @interval_live))
    |> calculate_medians()
    |> broadcast!("update-channel:#{@name}")
    |> write_to_database()

  do_your_thing(serial_pid) # repeat
end

我才刚刚开始弄清楚所有 OTP 的东西,希望你们中的某个人可以帮助我在这里找到正确的方向。

【问题讨论】:

    标签: elixir erlang-otp phoenix-framework


    【解决方案1】:

    您应该使用在 x 秒(下例中为 60 秒)后向自身发送消息的 GenServer:

    defmodule MyApp.Worker do
      use GenServer
    
      def start_link() do
        GenServer.start_link(__MODULE__, [])
      end
    
      def init([]) do
        schedule_work()
        {:ok, []}
      end
    
      def handle_info(:work, state) do
        state = do_work(state)
        schedule_work()
        {:noreply, state}
      end
    
      defp do_work(state) do
        # Do your work here and return state
      end
    
      defp schedule_work do
        Process.send_after(self(), :work, 60_000)
      end
    end
    

    【讨论】:

    • 为什么不让任务在无限循环中定期执行其工作(可能由 Stream.interval 或 Stream.repeatedly 提供支持)?如果这只是将拉取的数据进一步转发到系统的定期拉取,那么它实际上并不需要是 GenServer,对吧。任务仍然符合 OTP 标准,对我来说这似乎更直接。
    • 原因是Task收不到系统消息。我们想让 Stream 和朋友知道这些,但它不在 1.0 中,可能只会在 1.3 中。
    • 此外,您可能希望您的主管能够重新启动执行定期工作的工作人员,而不是在出现问题时让无限流崩溃当前进程。
    • @JoséValim 在 Elixir 1.3 中有更好的方法吗?
    • 谢谢何塞!我很高兴从最好的来源看到这个问题的答案。
    猜你喜欢
    • 2011-11-21
    • 2016-08-13
    • 2021-02-20
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-04
    • 2016-02-02
    相关资源
    最近更新 更多