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

Php 处理因错误而停止时RabbitMQ拒绝消息,php,symfony,rabbitmq,Php,Symfony,Rabbitmq,我正在为应用程序使用Symfony和RabbitMQ捆绑包,并遇到以下问题:当使用者服务引发未捕获的异常/错误(例如:内存不足)时,消息将被重新发布并一次又一次地使用,直到收到拒绝或确认信号。我希望更改此行为,以便在第一次使用消息时,如果出现任何未捕获的异常/错误,消息将被丢弃 这是否可能,如果可能,如何实现?谢谢 是的,您必须确认该消息。您可以通过将auto ack标志设置为true(取决于您使用的语言/API/库)或手动/显式确认消息来完成此操作。确认无法处理的消息是完全正常的,因为像您所说

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


这是否可能,如果可能,如何实现?谢谢

是的,您必须确认该消息。您可以通过将auto ack标志设置为true(取决于您使用的语言/API/库)或手动/显式确认消息来完成此操作。确认无法处理的消息是完全正常的,因为像您所说的那样,
消息会一次又一次地重新发布和使用

如果你愿意,你也可以。我不使用PHP来处理RabbitMQ,因此我不知道API的等价物是什么,也就是nack的实现位置/实现方式-在这种情况下(不是重新求值),最好配置(引用链接):

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

消息被拒绝(basic.reject或basic.nack),并带有 重新查询=错误,


看看下面的例子,它应该能解决你的问题。在这种情况下:

  • 消费者会像什么都没发生一样工作
  • 消息将从队列中丢弃
解决方案

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示例详细信息如下:。看起来选项2、3和4适用于您,这正是您试图通过问题的声音来避免的。

到目前为止,我能找到的最接近于此的解决方案是扩展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\u consume
方法的第四个参数称为
$no\u ack
,并设置为
false
。当此参数设置为
true
时,消息在处理后将被丢弃,而不管它是否引发了错误、异常或一切正常。因此,无论哪种方式,消息都会被丢弃


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

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

我不知道如何在RabbitMQBundle中实现这一点(但我完全相信这是可能的)。尽管我可以向您展示如何使用排队库:

<?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;
    }
}

谢谢,BentCoder!我熟悉ConsumerInterface常量,但我的问题是如何处理无法捕获的错误,即使是\Throwable错误,例如“内存不足”或“超出最大执行时间”。在这些情况下,消息将被重新发布。这可以/如何改变?如果确实存在这样一个选项,那么它必须属于RabbitMQ配置,因为PHP脚本已经停止。。。我读过关于auto ack标志的文章,据我所知,该标志在消息“经过”处理后会确认消息,但在RabbitMQ捆绑包中找不到任何方法。您看过symfony DLE的此回购吗@Medollock你有没有检查我的答案,将requeue选项设置为false部分?@BentCoder有趣的阅读,尝试过,但没有做我想要的。这是一种解决方案,适用于消费者返回“拒绝并重新申请”状态,而不是消费者被中断(突然停止)的情况。@cantSleepNow是的,但这不适用于这种情况,因为正如我上面提到的,消费者没有得到返回状态的更改。