1,首先确保rabbitmq安装了延迟队列插件
2,然后上代码,
先增加一个交换机类型:
<?php
/**
* Created by PhpStorm.
* User: haojin
* Date: 2020/7/9
* Time: 18:06
*/
namespace Chungou\Core\Amqp\Delay;
use Hyperf\Amqp\Message\Type;
class kinds extends Type
{
const X_DELAYED_MESSAGE = "x-delayed-message";
public static function all()
{
return [
self::DIRECT,
self::FANOUT,
self::TOPIC,
self::X_DELAYED_MESSAGE,
];
}
}
这是消费者代码
<?php
namespace Chungou\Core\Amqp\Delay;
use Hyperf\Amqp\Builder\ExchangeBuilder;
use Hyperf\Amqp\Message\ConsumerMessage;
use Hyperf\Amqp\Message\Message;
use PhpAmqpLib\Wire\AMQPTable;
//延迟队列
abstract class DelayConsumer extends ConsumerMessage
{
protected $type = 'x-delayed-message';
protected $delayType = "topic";
protected $argments = [];
public function setType(string $type): Message
{
if (!in_array($type, kinds::all())) {
throw new \InvalidArgumentException(sprintf('Invalid type %s, available valus [%s]', $type,
implode(',', kinds::all())));
}
$this->type = $type;
return $this;
}
public function getExchangeBuilder(): ExchangeBuilder
{
$this->argments = array_merge($this->argments, ['x-delayed-type' => $this->delayType]);
return (new ExchangeBuilder())->setExchange($this->getExchange())->setType($this->getType())->setArguments
(new AMQPTable($this->argments));
}
}
生产者:
<?php declare(strict_types=1);
/**
* Created by PhpStorm.
* User: haojin
* Date: 2020/6/18
* Time: 20:50
*/
namespace Chungou\Core\Amqp\Delay;
use Hyperf\Amqp\Builder\ExchangeBuilder;
use Hyperf\Amqp\Message\Message;
use Hyperf\Amqp\Message\ProducerMessage;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;
//延迟队列
abstract class DelayProducer extends ProducerMessage
{
protected $type = 'x-delayed-message';
protected $delayType = "topic";
protected $argments = [];
/**
* DelayProducer constructor.
* @param $data
* @param int $delay 延迟发送时间 毫秒
*/
public function __construct($data, int $delay = 0)
{
$this->payload = $data;
$this->properties['application_headers'] = new AMQPTable(['x-delay' => $delay]);
$this->properties['delivery_mode'] = AMQPMessage::DELIVERY_MODE_PERSISTENT;
}
public function setType(string $type): Message
{
if (!in_array($type, kinds::all())) {
throw new \InvalidArgumentException(sprintf('Invalid type %s, available valus [%s]', $type,
implode(',', kinds::all())));
}
$this->type = $type;
return $this;
}
public function getExchangeBuilder(): ExchangeBuilder
{
$this->argments = array_merge($this->argments, ['x-delayed-type' => $this->delayType]);
return (new ExchangeBuilder())->setExchange($this->getExchange())->setType($this->getType())->setArguments
(new AMQPTable($this->argments));
}
}
只需要继承这两个类就可以了
使用demo:
先定义一个生产者
<?php
namespace App\Amqp\Producer;
use Chungou\Core\Amqp\Delay\DelayProducer;
use Hyperf\Amqp\Annotation\Producer;
/**
* 延迟生产者
* @Producer(exchange="delayPlaceOrderExchange", routingKey="placeOrder")
*/
class DelayPlaceOrderProducer extends DelayProducer
{
}
定义一个消费者:
<?php declare(strict_types=1);
/**
* Created by PhpStorm.
* User: haojin
* Date: 2020/6/16
* Time: 11:34
*/
namespace App\Amqp\Consumer;
use App\Amqp\Producer\DelayPlaceOrderProducer;
use Chungou\Core\Amqp\Delay\DelayConsumer;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Producer;
use Hyperf\Amqp\Result;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\ApplicationContext;
/**
* insert订单,失败的话加入延迟队列
* @Consumer(exchange="delayPlaceOrderExchange", routingKey="placeOrder", queue="delayPlaceOrderQueue",
* name="placeOrder", nums=2)
*/
class PlaceOrderConsumer extends DelayConsumer
{
public function __construct(LoggerFactory $loggerFactory)
{
$this->poolName = 'default';
$this->logger = $loggerFactory->get('log', 'default');
}
public function consume($data): string
{
//如果小于5次则重发,并且每次延迟时间 多3秒
if ($data['retry'] <= 5) {
$delay = $data['retry'] * 3000;
$data['retry']++;
$producer = ApplicationContext::getContainer()->get(Producer::class);
$producer->produce(new DelayPlaceOrderProducer($data, $delay));
}
return Result::ACK;
}
}