Обработка ошибок потребителей в Symfony Messenger / RabbitMQ - PullRequest
0 голосов
/ 30 октября 2018

Я использую новый Symfony Messenger Component 4.1 и RabbitMQ 3.6.10-1, чтобы ставить в очередь и асинхронно отправлять уведомления по электронной почте и SMS из моего веб-приложения Symfony 4.1. Моя конфигурация Messenger (messenger.yaml) выглядит следующим образом:

framework:
    messenger:
        transports:
            amqp: '%env(MESSENGER_TRANSPORT_DSN_NOTIFICATIONS)%'

        routing:
            'App\NotificationBundle\Entity\NotificationQueueEntry': amqp

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

use Symfony\Component\Messenger\MessageBusInterface;
// ...
$notificationQueueEntry = new NotificationQueueEntry();
// [Set notification details such as recipients, subject, and message]
$this->messageBus->dispatch($notificationQueueEntry);

Затем я запускаю потребителя в командной строке следующим образом:

$ bin/console messenger:consume-messages

Я внедрил службу SendNotificationHandler, где происходит фактическая доставка. Конфигурация службы:

App\NotificationBundle\MessageHandler\SendNotificationHandler:
    arguments:
        - '@App\NotificationBundle\Service\NotificationQueueService'
    tags: [ messenger.message_handler ]

И класс:

class SendNotificationHandler
{
    public function __invoke(NotificationQueueEntry $entry): void
    {
        $this->notificationQueueService->sendNotification($entry);
    }
}

До этого момента все работает гладко и уведомления доставляются.

Теперь мой вопрос : Может случиться, что электронное письмо или SMS не могут быть доставлены из-за (временного) сбоя сети. В таком случае я хотел бы, чтобы моя система повторила доставку через указанное количество времени, вплоть до указанного максимального числа повторных попыток. Как можно достичь этого?

Я читал о Обмене мертвыми буквами , однако я не смог найти документацию или пример того, как интегрировать это с компонентом Symfony Messenger.

1 Ответ

0 голосов
/ 30 октября 2018

Что вам нужно сделать, это сказать RabbitMQ, что сообщение отклонено, а не подтверждено. По умолчанию мессенджер позаботится об этом внутри AmqpReceiver . Как вы можете видеть, если вы выбросите исключение, которое реализует RejectMessageExceptionInterface в вашем обработчике, сообщение будет автоматически отклонено для вас.

Вы также можете "смоделировать" это поведение с помощью специального промежуточного программного обеспечения. Я создал нечто подобное в небольшом демонстрационном приложении. Механизм состоит из промежуточного программного обеспечения, которое упаковывает (сериализованное) исходное сообщение в новое RetryMessage и отправляет его через пользовательскую шину сообщений в другую очередь, используемую в качестве обмена мертвыми буквами. Затем обработчик этого сообщения распакует RetryMessage (получает исходное сообщение и десериализует его) и передает его по шине по умолчанию:

См:

Это базовая настройка, которая отклоняет сообщение и позволяет мгновенно (!) Снова его использовать. Возможно, вы захотите добавить дополнительную информацию, такую ​​как заголовки для меток времени, при задержке потребления, чтобы улучшить это. Для этого вам следует написать собственный приемник, промежуточное программное обеспечение и / или обработчик.

...