Tp6操作Rabbitmq实例 直连模式 direct
官网下载 erlang和rabbitmq
rabbitmq下载地址
erlang下载地址
启动rabbitmq
进入rabbitmq控制台
控制台链接
composer 安装amqp类库
composer requirer php-amqplib/php-amqplib
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
);
}
}
}
// +----------------------------------------------------------------------
// | 控制台配置
// +----------------------------------------------------------------------
return [
// 指令定义
'commands' => [
'test:xxx' => "xxx\\command\\xxx\\xxx",// xxx
],
];
先用命令 php think 查看是否有 test:xxx 命令
执行队列:php think test:xxx