Làm cách nào tôi có thể lên lịch để chạy mã cứ sau vài giờ trong khung Elixir hoặc Phoenix?


193

Vì vậy, hãy nói rằng tôi muốn gửi một loạt email hoặc tạo lại sơ đồ trang web hoặc bất cứ điều gì cứ sau 4 giờ, tôi sẽ làm điều đó như thế nào ở Phoenix hoặc chỉ với Elixir?

Câu trả lời:


385

Có một cách thay thế đơn giản không yêu cầu bất kỳ sự phụ thuộc bên ngoài nào:

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

Bây giờ trong cây giám sát của bạn:

worker(MyApp.Periodically, [])

166
Không thể không yêu ngôn ngữ này :)
NoDisplayName 19/08/2015

3
Tôi nên đặt tập tin này ở đâu? Theo thư mục lib / của dự án Phoenix? Bài kiểm tra đi đâu, để kiểm tra / định kỳ / *?
EugZol

9
Trong lib vì nó là một quá trình dài. Bạn có thể đặt thử nghiệm bất cứ điều gì có ý nghĩa, có thể là "test / my_app / định_test.exs".
Jose Valim

2
Bất kỳ lý do cụ thể để không di chuyển Process.send_aftervào chức năng riêng của mình để chức năng có thể được gọi từ cả hai inithandle_info?
Ryan Bigg

24
@CodyPoll :timer.send_intervalvẫn ổn nhưng hãy nhớ rằng khoảng thời gian sẽ không đổi. Vì vậy, hãy tưởng tượng bạn muốn làm một cái gì đó mỗi phút và, trong tương lai, bản thân công việc mất hơn một phút. Trong những trường hợp như vậy, bạn sẽ làm việc mọi lúc và hàng đợi tin nhắn của bạn sẽ không bị ràng buộc. Giải pháp trên sẽ luôn chờ khoảng thời gian nhất định sau khi hoàn thành công việc.
Jose Valim

32

Lượng tử cho phép bạn tạo, tìm và xóa các công việc trong thời gian chạy.

Hơn nữa, bạn có thể chuyển các đối số cho hàm tác vụ khi tạo cronjob và thậm chí sửa đổi múi giờ nếu bạn không hài lòng với UTC.

Nếu ứng dụng của bạn đang chạy dưới dạng nhiều phiên bản riêng biệt (ví dụ Heroku), có bộ xử lý công việc được PostgreQuery hoặc Redis hỗ trợ, cũng hỗ trợ lập lịch tác vụ:

Oban: https://github.com/sorentwo/oban

Ví dụ: https://github.com/akira/exq

Tấn: https://github.com/joakimk/toniq

Verk: https://github.com/edgurgel/verk


1
Tôi nghĩ rằng nó sẽ là quá mức cho rất nhiều nhiệm vụ đơn giản không yêu cầu nhưng dù sao cũng cảm ơn bạn đã trả lời.
NoDisplayName

Có một danh sách các thư viện có sẵn là hữu ích cho tôi.
sheldonkreger

24

Bạn có thể sử dụng erlcron cho điều đó. Bạn sử dụng nó như thế nào

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

:erlcron.cron(job)

A joblà một tuple 2 phần tử. Phần tử đầu tiên là một tuple đại diện cho lịch trình cho công việc và phần tử thứ hai là chức năng hoặc MFA (Mô-đun, Chức năng, Arity). Trong ví dụ trên, chúng tôi chạy :io.fwrite("It's 2 Thursday morning")mỗi 2 giờ sáng thứ Năm.

Mong rằng sẽ giúp!


Vâng, tốt hơn là không có gì, cảm ơn bạn. Tôi sẽ để lại câu hỏi chưa được trả lời trong một thời gian, có thể sẽ có những gợi ý khác
NoDisplayName

4
Không có gì! Ngoài ra còn có github.com/c-rack/quantum-elixir là một thuốc
tiên dược

6

Tôi đã sử dụng thư viện lượng tử Quantum- Elixir .
Thực hiện theo các hướng dẫn dưới đây.

#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
]

Tất cả các thiết lập. Khởi động máy chủ bằng cách chạy bên dưới lệnh.

iex -S mix phoenix.server 

Điều này giống như cronjobs
DarckBlezzer

1

Tôi thấy :timer.send_interval/2hơi tiện dụng hơn khi sử dụng với GenServerhơn Process.send_after/4(được sử dụng trong câu trả lời được chấp nhận ).

Thay vì phải sắp xếp lại thông báo của bạn mỗi khi bạn xử lý nó, hãy :timer.send_interval/2thiết lập một khoảng thời gian mà bạn nhận được một tin nhắn vô tận. Không cần phải gọi schedule_work()như sử dụng câu trả lời được chấp nhận.

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

Cứ sau 1000 ms (tức là một lần một giây), IntervalServer.handle_info/2sẽ được gọi, in hiện tại countvà cập nhật trạng thái của GenServer ( count + 1), cung cấp cho bạn đầu ra như:

1
2
3
4
[etc.]


0

Lượng tử là tuyệt vời, chúng tôi sử dụng nó trong công việc như là một thay thế cron với mặt trước phượng hoàng và chúng tôi cũng thêm các công việc trong thời gian thực rất gọn gàng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.