tp使用Rabbitmq实例-延时重发队列

即时队列戳这里>即时队列

Tp6操作Rabbitmq实例 直连模式 direct

win本地安装

官网下载 erlang和rabbitmq
rabbitmq下载地址
erlang下载地址

启动rabbitmq
双击启动rabbitmq进程
在这里插入图片描述
进入rabbitmq控制台
控制台链接

在这里插入图片描述

composer 安装amqp类库
composer requirer php-amqplib/php-amqplib

整合rabbitmq代码


declare(strict_types=1);

namespace xxx\rabbitmq;

use ErrorException;
use Exception;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;

class RabbitMQ
{
    static private $instance;

    private   $host     = '127.0.0.1';
    private   $port     = 5672;
    private   $user     = 'guest';
    private   $password = 'guest';
    private   $vhost    = '/';
    protected $connection;
    protected $channel;

    /**
     * RabbitMQ constructor.
     * @param array $config
     */
    public function __construct(array $config = [])
    {
        !empty($config['host']) && $this->host = $config['host'];
        !empty($config['port']) && $this->host = $config['port'];
        !empty($config['user']) && $this->host = $config['user'];
        !empty($config['password']) && $this->host = $config['password'];
        !empty($config['vhost']) && $this->host = $config['vhost'];

        $this->connection = new AMQPStreamConnection($this->host, $this->port, $this->user, $this->password, $this->vhost);
        $this->channel    = $this->connection->channel();
    }

    /**
     * 实例化
     * @param array $config
     * @return RabbitMQ
     */
    public static function instance(array $config = [])
    {
        if (!self::$instance instanceof self) {
            self::$instance = new self($config);
        }
        return self::$instance;
    }

    /**
     * 防止被外部复制
     */
    private function __clone()
    {
    }

    /**
     * 获取信道
     * @return AMQPChannel
     */
    public function getChannel()
    {
        return $this->channel;
    }

    /**
     * 声明一个交换器
     * @param string $exchangeName 名称
     * @param string $type         交换机类型 :直连交换机(direct) 主题交换机 (topic) 头交换机(headers) 扇交换机(fanout)
     * @param bool   $pasive       是否检测同名队列
     * @param bool   $durable      是否开启队列持久化
     * @param bool   $autoDelete   通道关闭后是否删除队列
     */
    public function createExchange(
        string $exchangeName,
        string $type,
        bool $pasive = false,
        bool $durable = false,
        bool $autoDelete = false
    )
    {
        $this->channel->exchange_declare($exchangeName, $type, $pasive, $durable, $autoDelete);
    }

    /**
     * 创建队列
     * @param string $queueName
     * @param bool   $pasive
     * @param bool   $durable
     * @param bool   $exlusive
     * @param bool   $autoDelete
     * @param bool   $noWait
     * @param array  $arguments
     * @return mixed|null
     */
    public function createQueue(
        string $queueName,
        bool $pasive = false,
        bool $durable = false,
        bool $exlusive = false,
        bool $autoDelete = false,
        bool $noWait = false,
        array $arguments = []
    )
    {
        $args = [];
        if (!empty($arguments)) {
            $args = new AMQPTable();
            foreach ($arguments as $key => $value) {
                $args->set($key, $value);
            }
        }

        return $this->channel->queue_declare($queueName, $pasive, $durable, $exlusive, $autoDelete, $noWait, $args);
    }

    /**
     * 绑定队列
     * @param string   $queue
     * @param string   $exchangeName
     * @param string   $routeKey
     * @param bool     $noWait
     * @param array    $arguments
     * @param int|null $ticket
     */
    public function bindQueue(
        string $queue,
        string $exchangeName,
        string $routeKey = '',
        bool $noWait = false,
        array $arguments = [],
        $ticket = null
    )
    {
        $this->channel->queue_bind($queue, $exchangeName, $routeKey, $noWait, $arguments, $ticket);
    }

    /**
     * 生成信息
     * @param string $message    消息体
     * @param string $exchange   交换机
     * @param string $routeKey   路由key
     * @param array  $properties 属性
     * @param array  $headers
     */
    public function producerMessage(string $message, string $exchange, string $routeKey, array $properties = [], array $headers = [])
    {
        $data = new AMQPMessage($message, $properties);

        if (!empty($headers)) {
            $application_headers = new AMQPTable($headers);
            $data->set('application_headers', $application_headers);
        }

        $this->channel->basic_publish($data, $exchange, $routeKey);
    }

    /**
     * 消费消息
     * @param string $queueName
     * @param        $callback
     * @param string $tag
     * @param bool   $noLocal
     * @param bool   $noAck
     * @param bool   $exclusive
     * @param bool   $noWait
     * @throws ErrorException
     */
    public function consumeMessage(
        string $queueName,
        $callback,
        string $tag = '',
        bool $noLocal = false,
        bool $noAck = false,
        bool $exclusive = false,
        bool $noWait = false
    )
    {
        //只有consumer已经处理并确认了上一条message时queue才分派新的message给它
        $this->channel->basic_qos(null, 1, null);
        $this->channel->basic_consume($queueName, $tag, $noLocal, $noAck, $exclusive, $noWait, $callback);
        while ($this->channel->is_consuming()) {
            $this->channel->wait();
        }
    }

    /**
     * 关闭通道及链接
     * @throws Exception
     */
    public function __destruct()
    {
        //关闭通道
        $this->channel->close();
        //关闭链接
        $this->connection->close();
    }
}

延时重发队列使用

生产者队列:
		 // 延时结算
            $rabbitmq           = RabbitMQ::instance();
            $queue_name         = 'xxx';
            $exchange           = $queue_name . '.exchange';
            $queue              = $queue_name . '.queue';
            $routing_key        = $queue_name . '.routing_key';

            $dlx_exchange       = 'delay.' . $exchange;
            $dlx_queue          = 'delay.' . $queue;
            $dlx_routing_key    = 'delay.' . $routing_key;

            // 死信交换器
            $rabbitmq->createExchange($dlx_exchange, 'direct');
            // 死信队列
            $rabbitmq->createQueue($dlx_queue, false, true);
            // 绑定交换机、队列、路由key
            $rabbitmq->bindQueue($dlx_queue, $dlx_exchange, $dlx_routing_key);

            // 延迟交换机器
            $rabbitmq->createExchange($exchange, 'direct');

            $arguments = [
                'x-message-ttl'             => 1000,// 延迟时间(毫秒)队列中的消息1秒之后过期
                'x-dead-letter-exchange'    => $dlx_exchange,// 延迟结束后指向交换机(死信收容交换机)
                'x-dead-letter-routing-key' => $dlx_routing_key,// 延迟结束后指向队列(死信收容队列),可直接设置queue name也可以设置routing-key
            ];

            // 延迟队列
            $rabbitmq->createQueue($queue, false, true, false, false, false, $arguments);
            // 绑定交换机、队列、路由
            $rabbitmq->bindQueue($queue, $exchange, $routing_key);

            // 消息入队
            $rabbitmq->producerMessage(
                json_encode($data, JSON_UNESCAPED_UNICODE),
                $exchange,
                $routing_key,
                ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT],
                ['retry_nums' => 3]// 设置重试次数
            );
消费者队列:

declare (strict_types=1);

namespace manydads\command\device;

use ErrorException;
use Exception;
use PhpAmqpLib\Message\AMQPMessage;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Config;
use think\Model;

/**
 * xxx
 * Class xxxx
 * @package xxx
 */
class xxxextends Command
{
    protected function configure()
    {
        // 指令配置
        $this
            // 命令名称
            ->setName('xxx')
            // 运行 "php think list" 时的简短描述
            ->setDescription('xxx');
    }

    /**
     * @param Input  $input
     * @param Output $output
     * @return int|void|null
     * @throws ErrorException
     */
    protected function execute(Input $input, Output $output)
    {
        $rabbitmq   = RabbitMQ::instance();
        $queue_name = 'xxx';

        $dlx_exchange    = 'delay.' . $queue_name . '.exchange';
        $dlx_queue       = 'delay.' . $queue_name . '.queue';
        $dlx_routing_key = 'delay.' . $queue_name . '.routing_key';

        // 创建死信交换机
        $rabbitmq->createExchange($dlx_exchange, 'direct');
        // 创建死信队列
        $rabbitmq->createQueue($dlx_queue, false, true);
        // 绑定交换机、队列、路由
        $rabbitmq->bindQueue($dlx_queue, $dlx_exchange, $dlx_routing_key);
        // 消费消息
        $rabbitmq->consumeMessage($dlx_queue, [$this, 'onReceived']);
    }

    /**
     * 消费者回调方法
     * @param mixed $message 生产者发来的数据
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws Exception
     */
    public function onReceived($message)
    {
        $output      = new Output();
        $rabbitmq    = RabbitMQ::instance();
        $queue_name  = 'xxx';
        $exchange    = $queue_name . '.exchange';
        $routing_key = $queue_name . '.routing_key';

        $date_time = date('Y-m-d H:i:s');
        $output->writeln($date_time . ' Received ' . $message->body);

        //确认消息处理完成
        $message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);

        $message_data = json_decode($message->body, true);
        $status = $device_commands['status'];
        $error  = $device_commands['request_error'];
        $retry_nums  = 3;
        $msg_headers = $message->get('application_headers')->getNativeData();

         // 重试次数超过指定次数次,则超时
         if (intval($msg_headers['retry_nums']) >= $retry_nums) {
             $output->writeln($date_time . ' xxx下发的指令超时');

         } else {
             $msg = [];
             // 创建重试交换机
             $rabbitmq->createExchange($exchange, 'direct');
             // 放回重试队列
             $rabbitmq->producerMessage(
                 $message->body,
                 $exchange,
                 $routing_key,
                 ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT],
                 ['retry_nums' => intval($msg_headers['retry_nums']) + 1]// 重试次数加1
             );
         }
    }


}

console.php配置文件:

// +----------------------------------------------------------------------
// | 控制台配置
// +----------------------------------------------------------------------
return [
    // 指令定义
    'commands' => [
        'test:xxx'        => "xxx\\command\\xxx\\xxx",// xxx
    ],
];

cli执行:
先用命令 php think 查看是否有 test:xxx 命令
执行队列:php think test:xxx

你可能感兴趣的:(rabbitmq,php,rabbitmq,队列,交换机,php)