Долгое время я искал элегантные решения для создания и запуска фоновых заданий в PHP.

Я присоединился к компании, которая массово использовала Laravel, а Laravel поставляет с потрясающей системой Queue. Внезапно я забыл, насколько утомительно и хлопотно было писать очереди на PHP.

Но кажется, что очередь Laravel тесно связана с Laravel. У нас заканчиваются такие элегантные решения для приложений, которые не используют фреймворк Laravel.

Бернар спешит на помощь. Bernard - мощная библиотека PHP для создания и выполнения фоновых заданий в PHP. Согласно его вступлению в репозиторий Github:

Bernard - это многофункциональная PHP-библиотека для создания фоновых заданий для последующей обработки. Бернард делает фоновую обработку на PHP очень простой и приятной.

Но настроить Бернарда непросто, а документация недостаточно ясна. Итак, это моя попытка начать настройку Бернарда.

Концепции

Сообщение

Сообщение - это объект любого класса, реализующий Bernard\Message, который добавляется в фоновую очередь. Он представляет работу, которую нужно выполнить.

Режиссер

Производитель - это объект, который отправляет сообщение в нужную очередь.

Потребитель

Потребитель - это объект, который принимает сообщения из очереди и отправляет сообщение получателю сообщения для обработки задачи, указанной в сообщении.

Сериализатор

Сериализатор - это объект, который отвечает за:

  1. преобразование объекта сообщения в JSON для постоянного хранения
  2. преобразование JSON обратно в объект сообщения для использования сообщения Потребителем.

Водитель

Драйверы - это подключаемая система брокера сообщений, отвечающая за фактическую отправку сообщений от производителей к потребителям. В Бернарде Драйвер реализует Bernard\Driver. Существуют различные реализации на основе Redis, RabbitMQ и т. Д. Полный список можно найти на странице драйверов в официальной документации. Вот простой пример построения драйвера на основе predis/predis:

Простой пример

Создание сообщения

Здесь мы создали сообщение с именем SendForgotPasswordEmail и отправили его в очередь emails.

Потребляющее сообщение

Теперь нам нужно создать потребителя, который слушает очередь emails.

Использование более одной очереди

Расширенный пример:

Предположим, мы хотим общаться, используя объекты сообщений нашего собственного класса следующим образом:

Все хорошо до сих пор. Но Бернарду необходимо преобразовать объект сообщения в JSON, чтобы он мог сохранить сообщение в соответствующей очереди в формате JSON. По умолчанию Бернард поддерживает только Bernard\Message\PlainMessage.

По умолчанию Бернард может только нормализовать Bernard\Message\PlainMessage. Нам нужно настроить настраиваемый нормализатор для нормализации нашего настраиваемого объекта.

Мы добавили новый ObjectNormalizer, который может нормализовать любой объект. Вам необходимо установить пакет symfony/property-access, чтобы использовать этот нормализатор.

Теперь давайте создадим класс-обработчик для обработки задачи.

Назначение вызываемого обработчика заданий для каждого класса сообщений довольно утомительно. Что, если бы мы могли создать карту класса сообщения для его класса обработчика, как показано ниже, и загрузить обработчик по запросу.

Теперь мы можем попытаться разрешить объект-обработчик из контейнера внедрения зависимости. В этом посте я предполагаю, что внедрение зависимостей реализует PSR-11 ContainerInterface. Но приведенный ниже пример в большинстве случаев будет похож.

Теперь вот как будет выглядеть наш класс-обработчик:

Выглядит довольно чисто и, прежде всего, элегантно.

Лично я предпочитаю создавать абстрактный класс AbstractMessage class, который возвращает имя сообщения на основе полного имени класса, как показано ниже:

Вы также можете использовать прослушиватели присоединения к EventDispatcher в сценарии потребителя, как показано ниже:

Код окончательного результата доступен в этом репозитории.

Пожалуйста, не стесняйтесь копаться, и вы можете прокомментировать, если у вас есть лучший подход к ситуации.