Symfony Messenger / RabbitMQ中的消费者错误处理

时间:2018-10-30 15:59:04

标签: symfony rabbitmq dead-letter symfony-messenger

我正在使用新的Symfony Messenger Component 4.1和RabbitMQ 3.6.10-1来排队并从Symfony 4.1 Web应用程序异步发送电子邮件和SMS通知。我的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。在这种情况下,我希望我的系统在指定的时间段内重试交付,直到指定的最大重试次数。 要实现这一目标的方法是什么?

我已经读过Dead Letter Exchanges,但是,我找不到任何有关如何将其与Symfony Messenger组件集成的文档或示例。

1 个答案:

答案 0 :(得分:2)

您需要做的是告诉RabbitMQ,该消息被拒绝而不是被确认。默认情况下,Messenger会在AmqpReceiver内部处理此问题。如您所见,如果在处理程序中引发实现RejectMessageExceptionInterface的异常,则该消息将自动为您拒绝。

您还可以使用自定义中间件“模拟”此行为。我在一个小型演示应用程序中创建了类似的内容。该机制由中间件组成,该中间件将(序列化的)原始消息包装在新的RetryMessage中,并通过自定义消息总线将其发送到另一个队列,用作死信交换。然后,该消息的处理程序将解压缩RetryMessage(获取原始消息并反序列化)并通过默认总线进行传输:

请参阅:

这是一个基本设置,它拒绝该消息并允许您立即再次使用它(!)。您可能希望在延迟消耗时添加其他信息,例如时间戳标题,以改善此问题。为此,您应该考虑编写自己的接收器,中间件和/或处理程序。