Як я можу запланувати запуск коду кожні кілька годин у рамках Elixir або Phoenix?


194

Тож скажімо, що я хочу надсилати купу електронних листів або відтворювати мапу сайту чи будь-які інші кожні 4 години, як би це зробити у Phoenix чи просто з Elixir?

Відповіді:


390

Існує проста альтернатива, яка не потребує зовнішніх залежностей:

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, [])

170
Не можна не любити цю мову :)
NoDisplayName

3
Де я повинен помістити цей файл? Під lib / каталог проекту Phoenix? Куди йде тест, щоб перевірити / періодично / *?
EugZol

9
У lib тому, що це тривалий процес. Ви можете поставити тест у будь-якому сенсі, можливо "test / my_app / periodically_test.exs".
Жозе Валім

2
Якась конкретна причина не переходити Process.send_afterдо власної функції, щоб функцію можна було викликати і з initі handle_info?
Райан Бігг

24
@CodyPoll :timer.send_intervalчудово, але майте на увазі, що інтервали будуть постійними. Тож уявіть, що хочете щось робити щохвилини, і в майбутньому сама робота займає більше хвилини. У таких випадках ви будете працювати весь час, і ваша черга повідомлень зростатиме без обмежень. Наведене вище рішення завжди буде чекати заданого періоду після закінчення роботи.
Хосе Валім

33

Quantum дозволяє створювати, знаходити та видаляти завдання під час виконання.

Крім того, ви можете передавати аргументи функції завдання під час створення cronjob і навіть змінювати часовий пояс, якщо вас не влаштовує UTC.

Якщо ваш додаток працює як кілька ізольованих екземплярів (наприклад, Heroku), є процесори завдань, підтримувані PostgreSQL або Redis, які також підтримують планування завдань:

Обан: https://github.com/sorentwo/oban

Exq: https://github.com/akira/exq

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

Верк: https://github.com/edgurgel/verk


1
Я думаю, що це буде надлишком для багатьох простих завдань, які цього не потребують, але все одно дякую за відповідь.
NoDisplayName

Наявність у мене списку бібліотек було для мене корисним.
sheldonkreger

25

Ви можете використовувати erlcron для цього. Ви використовуєте це як

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

:erlcron.cron(job)

A job- двоярусний кортеж. Перший елемент - кортеж, який представляє графік роботи, а другий елемент - це функція або MFA (модуль, функція, Arity). У наведеному прикладі ми проводимо :io.fwrite("It's 2 Thursday morning")кожні 2 години ночі четверга.

Сподіваюся, що це допомагає!


Так, краще, ніж нічого, дякую. Я залишу питання на деякий час без відповіді, можливо, будуть інші пропозиції
NoDisplayName

4
Ласкаво просимо! Є також github.com/c-rack/quantum-elixir - це еліксир, якщо ви віддаєте перевагу
Gjaldon

6

Я використовував квантову бібліотеку 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/2трохи більш ергономічним для використання з ( GenServerніж 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буде викликано, надрукується поточний countта оновиться стан GenServer ( count + 1), даючи вихід, як:

1
2
3
4
[etc.]


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.