Як я можу запланувати запуск коду кожні кілька годин у рамках 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.