В этом посте мы рассмотрим, как использовать Oban, надежную систему фоновой обработки заданий для Elixir.

Язык Elixir имеет удивительную встроенную поддержку параллелизма и выполнения асинхронных задач в рамках Erlang OTP. Это правда: обычно вы можете просто отбрасывать задачи на задний план вашего приложения Elixir, не заботясь чрезмерно о параллелизме, производительности, блокировке и т. д.

Это хорошо работает для некоторых видов задач, но для других простой перевод задания в фоновый режим может иметь некоторые недостатки: что произойдет, если задание завершится ошибкой? Что произойдет, если сервер выйдет из строя? Как вы отслеживаете и управляете нагрузкой и параллелизмом?

Если такие сценарии имеют значение для вашего приложения, вам понадобится какая-то система для управления фоновыми заданиями. В этом посте мы рассмотрим Систему фоновой обработки заданий Oban. В частности, мы рассмотрим:

  • что такое обан и зачем он может понадобиться
  • как настроить и установить Oban в приложении Elixir
  • как определить и поставить в очередь фоновые задания
  • как запускать задания и управлять очередями

Давайте начнем!

Что такое Обан?

Oban — это высокопроизводительная система обработки фоновых заданий для языка Elixir. Это позволяет нам определять задания, помещать их в очереди и обрабатывать их в фоновом режиме, пока наше приложение выполняет другую работу. Задания постоянны, поэтому в случае сбоя сервера или процесса они не теряются. Oban будет обрабатывать логику повторных попыток и ошибок в этих сценариях. Кроме того, это позволяет нам отслеживать и управлять очередями заданий, чтобы мы могли следить за тем, сколько заданий обрабатывается, не выполняются ли задания и т. д.

Обан использует стандартную базу данных Postgres для сохранения и управления заданиями. Это отличается от некоторых других систем обработки заданий, которые могут использовать другие инструменты инфраструктуры, такие как Redis или RabbitMQ. Не вдаваясь в детальное сравнение производительности между этими различными инструментами, можно с уверенностью сказать, что добавление дополнительных сервисов в технический стек может значительно усложнить работу, поэтому использование Postgres — хорошая функция.

Если вы уже используете Postgres с Ecto (который используется по умолчанию в Phoenix), вы можете использовать существующую базу данных приложения, хотя вы также можете настроить альтернативную базу данных, если хотите. Если вы не работаете в очень больших масштабах, лучше всего начать с использования базы данных приложения по умолчанию.

Хотя Oban работает с любым приложением Elixir, это естественный выбор для веб-приложений, созданных с помощью фреймворка Phoenix. Веб-приложения ориентированы на взаимодействие в реальном времени и быстрые ответы, поэтому часто имеет смысл выполнять определенные задачи в фоновом режиме. Например, если приложение отправляет приветственное письмо новому пользователю при регистрации, нет смысла ждать завершения доставки в середине веб-запроса. Лучше немедленно отобразить страницу и поместить доставку электронной почты в фоновую очередь.

Хотя Oban имеет открытый исходный код и бесплатен для использования, они предлагают дополнительные функции Pro, включая чрезвычайно удобный веб-интерфейс для мониторинга и управления очередями заданий среди других функций.

Запуск фоновых заданий с Oban

Теперь, когда у нас есть фон на Обане (ужасный каламбур), давайте посмотрим, как установить и использовать Обана в нашем приложении Elixir.

Установка Обана

Большая часть этого раздела представляет собой краткий обзор того, что описано в документации Oban, но он включен сюда, чтобы помочь вам начать работу. См. полную документацию, чтобы узнать больше о дополнительных параметрах конфигурации.

Во-первых, вам нужно установить Oban в свое приложение, добавив oban в файл mix.exs и запустив mix deps.get:

# mix.exs 
def deps do 
  [ {:oban, "~> 2.13"} ] 
end

Oban будет использовать наш существующий репозиторий Ecto (обычно Postgres) для сохранения заданий. Нам нужно создать миграцию, которая создает и настраивает необходимую таблицу:

mix ecto.gen.migration add_oban_jobs_table

А затем в сгенерированной миграции:

defmodule MyApp.Repo.Migrations.AddObanJobsTable do
  use Ecto.Migration 
  def up do 
    Oban.Migrations.up(version: 11) 
  end 
  def down do 
    Oban.Migrations.down(version: 1) 
  end 
end

Наконец, мы настроим Oban в нашем config/config.exs:

config :my_app, Oban, 
  repo: MyApp.Repo, 
  plugins: [Oban.Plugins.Pruner], 
  queues: [default: 10]

Чтобы наши фоновые задания выполнялись сразу при запуске тестов, мы также добавим конфигурацию в config/test.exs:

# config/test.exs 
config :my_app, Oban, testing: :inline

Полный список опций конфигурации доступен в Документации Oban.Config.

Определение задания

Определить наши фоновые задания с Oban очень просто. Мы просто создаем модуль, который использует Oban.Worker, указывает некоторые параметры и определяет функцию perform для выполнения:

defmodule MyApp.MyImportantJob do 
  use Oban.Worker, queue: :events 
  @impl Oban.Worker 
  def perform(%Oban.Job{args: args}) do 
    IO.inspect(args) :ok 
  end 
end

В приведенном выше примере мы указываем только, в какую очередь должно быть помещено задание, но есть и другие параметры, которые также можно указать:

use Oban.Worker, 
  queue: :events, 
  priority: 3, 
  max_attempts: 3, 
  tags: ["user"], 
  unique: [period: 30]

См. Документацию Worker для получения полной информации о доступных опциях.

Постановка в очередь и выполнение

Создать задание так же просто, как создать задание с нужными параметрами и вызвать Oban.Insert(), чтобы поставить его в очередь.

MyApp.MyImportantJob.new(%{id: 1, params: []}) 
  |> Oban.insert()

Теперь наше задание поставлено в очередь, но оно еще не будет выполнено, так как мы еще не запустили нашу очередь. Если вам интересно, на этом этапе вы можете сделать паузу и проверить базу данных Postgres, чтобы увидеть поставленное в очередь задание. В нашей таблице oban_jobs вы должны найти задание, которое мы только что поставили в очередь в состоянии available:

1 | available | events | MyApp.MyImportantJob | {"x": 10} | ...

Когда мы будем готовы запустить наши задания, нам останется только запустить очередь! Мы делаем это с помощью вызова Oban.start_queue с именем очереди и пределом параллелизма:

Oban.start_queue(queue: :events, limit: 4)

Обратите внимание, что если у нас определено несколько очередей, мы можем запускать и останавливать их независимо и с разными параметрами.

В этом простом примере наше задание просто проверяет содержимое предоставленных args, поэтому, когда мы запускаем очередь, мы должны видеть сообщения журнала, выводимые на консоль. В «настоящей» работе мы, вероятно, выполнили бы какое-то действие и сохранили бы результат обратно в базу данных.

Следующие шаги

Теперь, когда мы рассмотрели основы Oban, мы знаем достаточно, чтобы начать использовать его в нашем приложении Elixir для запуска простых фоновых заданий, но есть много других вещей, которые Oban может делать, которые мы не рассмотрели, например:

Какое бы приложение Elixir вы ни создавали, использование Oban для управления фоновыми заданиями — отличное дополнение к набору инструментов.

А если вы хотите узнать больше о создании приложений с помощью Elixir и Phoenix, ознакомьтесь с этими соответствующими статьями!





Первоначально опубликовано на https://blixtdev.com 28 октября 2022 г.

Джонатан имеет более чем 20-летний опыт руководства крупными и малыми стартапами.