如何安排代码在Elixir或Phoenix框架中每隔几个小时运行一次?


193

因此,假设我想每隔4个小时发送一堆电子邮件或重新创建站点地图,或者其他任何事情,我将如何在Phoenix或仅使用Elixir做到这一点?

Answers:


385

有一个简单的替代方法,不需要任何外部依赖项:

defmodule MyApp.Periodically do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, %{})
  end

  def init(state) do
    schedule_work() # Schedule work to be performed at some point
    {:ok, state}
  end

  def handle_info(:work, state) do
    # Do the work you desire here
    schedule_work() # Reschedule once more
    {:noreply, state}
  end

  defp schedule_work() do
    Process.send_after(self(), :work, 2 * 60 * 60 * 1000) # In 2 hours
  end
end

现在在您的监督树中:

worker(MyApp.Periodically, [])

166
不爱这种语言是不可能的:)
NoDisplayName 2015年

3
我应该把这个文件放在哪里?在Phoenix项目的lib /目录下?测试在哪里进行/定期/ *进行测试?
EugZol 2015年

9
在lib中,因为它是一个长期运行的过程。您可以进行任何有意义的测试,例如“ test / my_app / periodically_test.exs”。
何塞·瓦利姆(JoséValim)2015年

2
是否有任何特殊原因不Process.send_after进入自己的函数,以便可以从init和调用函数handle_info
瑞安·比格

24
@CodyPoll :timer.send_interval很好,但请记住,间隔将保持不变。因此,想象一下您想每分钟做某件事,并且在将来,工作本身需要花费一分钟以上的时间。在这种情况下,您将一直在工作,并且消息队列将变得无限。上面的解决方案将在工作完成始终等待给定时间。
何Valim

32

Quantum使您可以在运行时创建,查找和删除作业。

此外,在创建cronjob时,您可以将参数传递给task函数,如果您对UTC不满意,甚至可以修改时区。

如果您的应用程序作为多个隔离的实例(例如Heroku)运行,则有PostgreSQL或Redis支持的作业处理器,它们也支持任务调度:

奥本(Oban):https : //github.com/sorentwo/oban

例题:https//github.com/akira/exq

Toniq:https//github.com/joakimk/toniq

威客:https//github.com/edgurgel/verk


1
我认为对于许多不需要它的简单任务来说,这将是一个过大的杀伤力,但是无论如何,谢谢您的回答。
NoDisplayName

列出可用的库对我很有帮助。
sheldonkreger

24

您可以为此使用erlcron。你用它像

job = {{:weekly, :thu, {2, :am}},
  {:io, :fwrite, ["It's 2 Thursday morning~n"]}}

:erlcron.cron(job)

A job是2元素元组。第一个元素是代表作业计划的元组,第二个元素是函数或MFA(模块,函数,Arity)。在上面的示例中,我们:io.fwrite("It's 2 Thursday morning")每星期四凌晨2点运行一次。

希望有帮助!


是的,总比没有好,谢谢。我将在一段时间内不回答这个问题,也许还会有其他建议
NoDisplayName 2015年

4
别客气!如果您愿意的话,还有github.com/c-rack/quantum-elixir,这是一个
万能药库

6

我使用了Quantum库Quantum- Elixir
请遵循以下指示。

#your_app/mix.exs
defp deps do
  [{:quantum, ">= 1.9.1"},  
  #rest code
end



#your_app/mix.exs
def application do
  [mod: {AppName, []},
   applications: [:quantum,
   #rest code         
 ]]
end

#your_app/config/dev.exs
config :quantum, :your_app, cron: [
  # Every minute
  "* * * * *": fn -> IO.puts("Hello QUANTUM!") end
]

可以了,好了。通过运行以下命令来启动服务器。

iex -S mix phoenix.server 

这就像cronjobs
DarckBlezzer

1

我发现:timer.send_interval/2GenServer相比使用更符合人体工程学Process.send_after/4(用于公认的答案)。

不必在每次处理通知时都重新安排您的通知,而是:timer.send_interval/2设置一个不断接收消息的时间间隔-无需schedule_work()像接受的答案那样继续打电话。

defmodule CountingServer do
  use GenServer

  def init(_) do
    :timer.send_interval(1000, :update)
    {:ok, 1}
  end

  def handle_info(:update, count) do
    IO.puts(count)
    {:noreply, count + 1}
  end
end

每隔1000毫秒(即每秒一次)IntervalServer.handle_info/2将被调用,输出current count,并更新GenServer的状态(count + 1),为您提供如下输出:

1
2
3
4
[etc.]


0

Quantum很棒,我们在工作中将其用作凤凰前端的cron替代品,而且我们还实时添加了非常整洁的作业。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.