当处理因错误而停止时,RabbitMQ拒绝消息

时间:2016-11-05 17:28:14

标签: php symfony rabbitmq

我正在为应用程序使用Symfony和RabbitMQ包,并遇到以下问题:当消费者服务抛出未捕获的异常/错误(例如:内存不足)时,消息将被重新发布并一次又一次地使用,直到它获得拒绝或确认信号。我想更改此行为,以便在第一次消息消息时发生任何未捕获的异常/错误时丢弃该消息。

这是可能的,如果是的话,怎么样?谢谢!

4 个答案:

答案 0 :(得分:1)

是的,您必须确认消息。您可以通过将auto-ack标志设置为true(取决于您正在使用的语言/ API /库)或手动/明确地确认消息来执行此操作。无法处理无法处理的消息是完全正常的,因为除此之外,就像你说message is republished and consumed again and again一样。

如果您还想要,也可以set requeue to false。我没有使用PHP来处理RabbitMQ所以我不知道什么是API等价物,那就是 nack 的实现地点/方式 - 在这种情况下(不要重新说明是)配置dead letter exchange(链接引用)可能是个好主意:

  

来自队列的消息可以是“死信”'也就是说,重新发布到   发生以下任何事件时的另一次交换:

     

邮件被拒绝(basic.reject或basic.nack)   重新排队=假,
  ...

答案 1 :(得分:0)

看一下下面的示例,它可以解决您的问题。在这种情况下:

  • 消费者会好像什么都没发生一样。
  • 将从队列中丢弃消息。

解决方案

class OrderCreateConsumer implements ConsumerInterface
{
    public function execute(AMQPMessage $message)
    {
        $body = json_decode($message->body, true);

        try {
            // Do whatever you want with $body
        } catch (Exception $e) {
            return ConsumerInterface::MSG_REJECT;
        }
    }
}

或者完整的symfony + RabbitMQ示例详细信息在此处:The proper ways of handling errors in symfony RabbitMQ consumer。看起来选项2,3和4适用于您,这是您试图通过问题的声音避免的。

答案 2 :(得分:0)

我能找到的最近的解决方案是扩展RabbitMq包。在BaseConsumer类(名称空间OldSound\RabbitMqBundle\RabbitMq)中,有一个名为setupConsumer的方法,如下所示:

protected function setupConsumer()
{
    if ($this->autoSetupFabric) {
        $this->setupFabric();
    }
    $this->getChannel()->basic_consume($this->queueOptions['name'], $this->getConsumerTag(), false, false, false, false, array($this, 'processMessage'));
}

basic_consume方法的第四个参数称为$no_ack,并设置为false。当此参数设置为true时,消息在处理后将被丢弃,无论它是否发生错误,或者它是否引发了异常,或者一切顺利。因此,无论如何都会丢弃消息。

请记住,当$no_ack参数设置为true时,消费者返回的状态无关紧要,因此返回ConsumerInterface::MSG_REJECT_REQUEUE将无效 - 消息仍然被丢弃。

答案 3 :(得分:0)

AMQP协议为我们提供了一条消息redelivered property

我不知道如何在RabbitMQBundle中做到这一点(但我完全相信它是可能的)。虽然我可以告诉你如何使用Enqueue lib:

<?php

use Enqueue\Psr\PsrContext;
use Enqueue\Psr\PsrMessage;
use Enqueue\Psr\PsrProcessor;

class FooProcessor implements PsrProcessor
{
    public function process(PsrMessage $message, PsrContext $context)
    {
        if ($message->isRedelivered()) {
            // we already tried to process this message and failed. 

            return self::REJECT;
        }

        // this is the new message we've never seen before. 

        // do the job

        return self::ACK;
    }
}

解决此类问题的另一种方法是延迟重新传递的消息,这可能与RabbitMQBundle有关,但您必须手动配置每个部分,其中enqueue bundle执行此操作。您只需设置延迟插件并打开配置选项即可。 post

中的更多内容

尝试捕获始终不可靠。您可能会收到一个错误,例如致命错误,无法获取。

自动确认模式也不好,因为您可能会在没有任何通知或警告或恢复能力的情况下丢失失败的消息。