Php RabbitMQ:从DLX绑定

Php RabbitMQ:从DLX绑定,php,rabbitmq,amqp,php-amqplib,Php,Rabbitmq,Amqp,Php Amqplib,我已经搜索了该信息(包括)但找不到 我正在使用RabbitMQ v的最新版本。2.7.1. 我有三个队列和三个交换台: // Declare the exchanges $this->channel->exchange_declare(self::EXCHANGE_TO_PROCESS, 'direct', false, true, false, false, false); $this->channel->exchange_declare(self::EXCHANGE_

我已经搜索了该信息(包括)但找不到

我正在使用RabbitMQ v的最新版本。2.7.1. 我有三个队列和三个交换台:

// Declare the exchanges
$this->channel->exchange_declare(self::EXCHANGE_TO_PROCESS, 'direct', false, true, false, false, false);
$this->channel->exchange_declare(self::EXCHANGE_WAITING, 'direct', false, true, false, false, false);
$this->channel->exchange_declare(self::EXCHANGE_TO_CLEAN, 'direct', false, true, false, false, false);

// Messages in the to_process queue are sent to to_clean after 24 hours without being processed
$this->channel->queue_declare(self::QUEUE_TO_PROCESS, false, true, false, false, false, array(
    'x-dead-letter-exchange' => array('S', self::EXCHANGE_TO_CLEAN),
    'x-message-ttl' => array('I', 86400000), // 1 day in milli-seconds
));

// Messages in the waiting queue are sent to to_process after 5 minutes (wait period before retry)
$this->channel->queue_declare(self::QUEUE_WAITING, false, true, false, false, false, array(
    'x-dead-letter-exchange' => array('S', self::EXCHANGE_TO_PROCESS),
    'x-message-ttl' => array('I', 300000), // 5 minutes in milli-seconds
));

// Messages in the to_clean queue are kept until they are processed
$this->channel->queue_declare(self::QUEUE_TO_CLEAN, false, true, false, false, false);

// Bind the queues to the exchanges
$this->channel->queue_bind(self::QUEUE_TO_PROCESS, self::EXCHANGE_TO_PROCESS);
$this->channel->queue_bind(self::QUEUE_TO_CLEAN, self::EXCHANGE_TO_CLEAN);
$this->channel->queue_bind(self::QUEUE_WAITING, self::EXCHANGE_WAITING);
行为非常简单:消息被发布到
交换\u到\u过程中。外部工作者处理消息:如果处理进行得很顺利,消息将被简单地确认,从而从队列中删除(这一部分工作得很好);如果处理出错,则将消息插入
EXCHANGE\u WAITING
中,在TTL 5分钟后,通过DLX将消息重新插入
EXCHANGE\u-TO\u进程中进行重新处理。但是,在第三次失败之后,它会被插入到
交换\u TO \u CLEAN
中,其中会出现cron作业并清理消息、日志错误等

然而,我遇到的问题是,代码清楚地将
队列等待
绑定到
交换等待
(如预期),但当我查看RabbitMQ管理页面时,我注意到两个队列绑定到该交换,即
队列等待进程
队列等待
,按这个顺序。当这5分钟结束时,信息就会消失。我不太清楚为什么

所有这些让我们想到我的问题:死信交换是否隐式地将exchangein参数绑定到队列?还有:我丢失的信息可能会发生什么情况

编辑

我甚至比以前更困惑了。我尝试了以下非常基本的代码:

    $this->channel->exchange_declare('exchangeA', 'fanout', false, true, false, false, false);
    $this->channel->exchange_declare('exchangeB', 'fanout', false, true, false, false, false);
    $this->channel->queue_declare('queueA', false, true, false, false, false, array(
        'x-dead-letter-exchange' => array('S', 'exchangeB'),
        'x-message-ttl' => array('I', 5000)
    ));
    $this->channel->queue_declare('queueB', false, true, false, false, false);
    $this->channel->queue_bind('queueA', 'exchangeA');
    $this->channel->queue_bind('queueB', 'exchangeB');

    $msg = new AMQPMessage('hello!');
    $this->channel->basic_publish($msg, 'exchangeA');

这将创建两个队列和两个交换(我已经看到它们扇出以避免路由键的麻烦),将queueA绑定到exchangeA,将queueB绑定到exchangeB,并将queueA上的TTL及其DLX设置为exchangeB。在查看管理页面中发生的情况时,我看到一条消息如预期在queueA中花费了5秒钟,然后该消息消失,就像我上面更复杂的代码一样。

看起来您的消息流可能会循环。如果是这样,RabbitMQ将按照官方文档(第节)中的规定自动删除消息:

有可能形成一个死信队列循环。例如, 当队列将死信消息发送到默认值时,可能会发生这种情况 交换而不指定死信路由密钥。中的消息 此类循环(即两次到达同一队列的消息)将 如果整个周期是由于消息过期而导致,则丢弃

要解决自行车问题,您必须选择一个选项:

  • 完全打破循环(在某个点上丢弃消息)
  • 使用暂停队列中的消息,并根据您的工作流手动重新发布它们
  • 这会给您的应用程序带来一些复杂性,但这是您必须为性能和稳定性付出的代价

    附言:

    我在RabbitMQ邮件列表中找到了类似的问题,比如你的-:

    此时,您必须消费并重新发布以清除 RabbitMQ外部的标头


    当我偶然发现并看到海报上有一个与我们非常相似的箱子时,我怀疑有什么地方出了问题,他说它工作正常,没有问题。。。所以我开始多挖一点

    我们遇到的问题只是版本问题。我被告知RabbitMQ软件包是最新的,但我们使用的是Ubuntu12.04 LTS,所以“最新”版本是2.7.1——一个超过3年的版本


    如果您的情况与我们相同(使用较旧的发行版),请签出RabbitMQ并选择适合您的发行版的版本。在的情况下,我们只需添加正式的repo(您也可以简单地下载.dpkg文件),执行
    apt get update
    ,然后等待服务器重新启动。之后,上面的代码基本正常工作。

    请澄清您使用的是什么php库(或扩展)。事实上,没有指定:我使用的是最新版本的php amqplib。我添加了正确的标签,我将更新问题的文本。谢谢你的回答,这似乎是我的问题。你对我该如何处理这个问题有什么建议吗?例如,我可以再创建两个队列(比如failure1和failure2),处理失败的消息将被发送到其中,但这似乎有点不雅观和过分,但如果您有更好的解决方案,我洗耳恭听。手动使用
    self::QUEUE\u WAITING
    中的消息,然后将它们发布到
    self::EXCHANGE\u-to\u流程
    “按原样”(使用相同的路由密钥)。事实上,我还建议您对任务只使用一次交换,但使用
    x-dead-letter-routing-key
    电源(除非您有理由这样做)。但您的工作流也可以,但实体较少对我来说似乎更干净。还使用解决方案更新了我的答案,以处理rabbitmq循环保护。