Hyperf框架实现Rabbitmq延迟队列

Hyperf框架实现Rabbitmq延迟队列

Hyperf框架官方支持了Amqp,但是只是具备了基础发消息和接受消息。对于我们经常使用的延迟队列却不支持,这让人感到痛苦。

设计延迟队列

在这里插入图片描述
由于Rabbitmq默认没有支持延迟队列,需要使用官方的TTL和死信队列来实现我们的延迟队列功能.

实现原理:

1、rabbitmq 可以针对 Queue和Message 设置 x-message-ttl 来控制消息的生存时间,如果超时,消息变为 dead letter

2、rabbitmq 的queue 可以配置 x-dead-letter-exchange 和 x-dead-letter-routing(可选) 两个参数,来控制队列出现 dead letter 的时候,重新发送消息的目的地

注意事项:

1、设置了 x-dead-letter-exchange 和 x-dead-letter-routing 后的队列是根据队列入队的顺序进行消费,即使到了过期时间也不会触发x-dead-letter-exchange因为过期时间是在消息出队列的时候进行判断的

2、所以当队列没有设过期时间时,插入一个没有过期时间的消息会导致 x-dead-letter-exchange 队列永远不会被消费

分析&实现Hyperf延迟队列

通过看源码可以发现,Hyperf对Rabbitmq的官方SDK php-amqplib/php-amqplib 进行了封装。要实现延迟队列首先要了解清楚如果通过 php-amqplib/php-amqplib 实现延迟队列(参考下方 php-amqplib实现延迟队列)。

消息提供者

通过debug可以看到 hyperf 的producer仅仅是将消息推送至交换器就结束了。根据设计需要根据消息的过期时间建立对应的延迟queue 所以通过改造实现成下面这样:

declare(strict_types=1);

namespace App\Constants\Amqp;

use Hyperf\Amqp\Builder;
use Hyperf\Di\Annotation\AnnotationCollector;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;

class DelayProducer extends Builder
{
    public function produce(DelayProducerMessage $producerMessage, bool $confirm = false, int $timeout = 5, $delayTime = 0): bool
    {
        return retry(1, function () use ($producerMessage, $confirm, $timeout, $delayTime) {
            return $this->produceMessage($producerMessage, $confirm, $timeout, $delayTime);
        });
    }

    /**
     * @param DelayProducerMessage $producerMessage
     * @param bool $confirm
     * @param int $timeout
     * @param int $delayTime
     * @return bool
     * @throws \Throwable
     */
    private function produceMessage(DelayProducerMessage $producerMessage, bool $confirm = false, int $timeout = 5, int $delayTime = 0)
    {
        $result = false;

        $this->injectMessageProperty($producerMessage);

        if ($delayTime > 0) {
            $message = new AMQPMessage($producerMessage->payload(), array_merge($producerMessage->getProperties(), [
                'expiration' => $delayTime * 1000,
            ]));
        } else {
            $message = new AMQPMessage($producerMessage->payload(), $producerMessage->getProperties());
        }

        $pool = $this->getConnectionPool($producerMessage->getPoolName());
        /** @var \Hyperf\Amqp\Connection $connection */
        $connection = $pool->get();
        if ($confirm) {
            $channel = $connection->getConfirmChannel();
        } else {
            $channel = $connection->getChannel();
        }
        $channel->set_ack_handler(function () use (&$result) {
            $result = true;
        });

        try {
             $delayExchange   = 'delayed_' . $producerMessage->getExchange();
            $delayQueue      = 'delayed_queue_' . $producerMessage->getExchange() . $producerMessage->getTtl() . '_' . $delayTime;
            $delayRoutingKey = $producerMessage->getRoutingKey() . $delayTime;
            //定义延迟交换器
            $channel->exchange_declare($delayExchange, 'topic', false, true, false);

            //定义延迟队列
            $channel->queue_declare($delayQueue, false, true, false, false, false, new AMQPTable(array(
                "x-dead-letter-exchange"    => $producerMessage->getExchang
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值