Несколько автобусов

Дата обновления перевода 2024-07-25

Несколько автобусов

Распространенной архитектурой при создании приложений является разделение команд и запросов. Команды - это действия, которые что-то делают, а запросы - извлекают данные. Это называется CQRS (Разделение назначений запросов и команд). Прочтите статью о CQRS Мартина Фоулера, чтобы узнать больше. Эта архитектура может быть использована совместно с компонентом Messenger путем определения нескольких автобусов.

Автобус команд немного отличается от автобуса запросов. К примеру, автобусы команд обычно не предоставляют никаких результатов, а автобусы запросов редко бывают асинхронными. Вы можете сконфигурировать эти автобусы и их правила, используя промежуточное ПО.

Еще может быть хорошей идеей разделять действия от реакций, путем введения автобуса событий. Автобус событий может иметь 0 и более подписчиков.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
framework:
    messenger:
        # Автобус, который будет внедрен при внедрении MessageBusInterface
        default_bus: command.bus
        buses:
            command.bus:
                middleware:
                    - validation
                    - doctrine_transaction
            query.bus:
                middleware:
                    - validation
            event.bus:
                default_middleware:
                    enabled: true
                    # установить "allow_no_handlers" как true (false по умолчанию), чтобы разрешить
                    # отсутствие сконфигурированного обработчика для этого автобуса, без вызова исключения
                    allow_no_handlers: false
                    # установить "allow_no_senders" как false (true по умолчанию), чтобы вызвать исключение,
                    # если для этого автобуса не сконфигурирован отправитель
                    allow_no_senders: true
                middleware:
                    - validation

6.2

Опция allow_no_senders была представлена в Symfony 6.2.

Это создаст три новых сервиса:

  • command.bus: автомонтируемый с подсказкой MessageBusInterface (так как это default_bus);
  • query.bus: автомонтируемый с помощью MessageBusInterface $queryBus;
  • event.bus: автомонтируемый с помощью MessageBusInterface $eventBus.

Ограничение обработчиков по автобусам

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

1
2
3
4
5
6
7
# config/services.yaml
services:
    App\MessageHandler\SomeCommandHandler:
        tags: [{ name: messenger.message_handler, bus: command.bus }]
        # предотвращает обработчиков от двойной регистрации (или вы можете удалить
        # MessageHandlerInterface, который автоконфигуратор использует для обнаружения обработчиков)
        autoconfigure: false

Таким образом, обработчик App\MessageHandler\SomeCommandHandler будет известен только автобусу command.bus.

Вы также можете автоматически добавить этот тег к определенному количеству классов, используя _экземпляр конфигурации сервиса . Используя это, вы сможете определить автобус сообщений, основываясь на реализованном интерфейсе:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# config/services.yaml
services:
    # ...

    _instanceof:
        # все сервисы, реализующие CommandHandlerInterface
        # будут зарегистрированы в автобусе command.bus
        App\MessageHandler\CommandHandlerInterface:
            tags:
                - { name: messenger.message_handler, bus: command.bus }

        # в то время как те, что реализуют QueryHandlerInterface, будут
        # зарегистрированы в автобусе query.bus
        App\MessageHandler\QueryHandlerInterface:
            tags:
                - { name: messenger.message_handler, bus: query.bus }

Отладка автобусов

Команда debug:messenger перечисляет доступные сообщения и обработчики для каждого автобуса. Вы также можете ограничить список по определенному автобусу, предоставив его название в качестве аргумента.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ php bin/console debug:messenger

  Messenger
  =========

  command.bus
  -----------

   Следующие сообщения могут быть запущены:

   ---------------------------------------------------------------------------------------
    App\Message\DummyCommand
        handled by App\MessageHandler\DummyCommandHandler
    App\Message\MultipleBusesMessage
        handled by App\MessageHandler\MultipleBusesMessageHandler
   ---------------------------------------------------------------------------------------

  query.bus
  ---------

   Следующие сообщения могут быть запущены:

   ---------------------------------------------------------------------------------------
    App\Message\DummyQuery
        handled by App\MessageHandler\DummyQueryHandler
    App\Message\MultipleBusesMessage
        handled by App\MessageHandler\MultipleBusesMessageHandler
   ---------------------------------------------------------------------------------------

Tip

Команда также будет отображать описание сообщения PHPDoc и классы обработчика.