В этом посте мы рассмотрим, как использовать 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 может делать, которые мы не рассмотрели, например:
- Запланированные задания (аналог cron)
- Дедупликация заданий
- Поддержка кластеризации для нескольких обработчиков заданий
Какое бы приложение Elixir вы ни создавали, использование Oban для управления фоновыми заданиями — отличное дополнение к набору инструментов.
А если вы хотите узнать больше о создании приложений с помощью Elixir и Phoenix, ознакомьтесь с этими соответствующими статьями!
Первоначально опубликовано на https://blixtdev.com 28 октября 2022 г.
Джонатан имеет более чем 20-летний опыт руководства крупными и малыми стартапами.