Rabbitmq - TP6应用
1.配置文件
<?php
// +----------------------------------------------------------------------
// | rabbitMQ 示例配置
//
// Exchange在定义的时候是有类型的,以决定到底是哪些Queue符合条件,可以接收消息:
// fanout:所有bind到此exchange的queue都可以接收消息
// direct:通过routingKey和exchange决定的那个唯一的queue可以接收消息
// topic:所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息
// headers:通过headers 来决定把消息发给哪些queue(这个很少用)
// x-delayed-message:插件安装,延迟模式
// +----------------------------------------------------------------------
return [
'AMQP' => [
'host' => '127.0.0.1',
'vhost' => '/',
'port' => '5672',
'user' => 'admin',
'password' => 'admin'
],
'dead_queue_info' => [
'dead_queue_name' => 'dead_queue',
'dead_exc_name' => 'dead-exc',
'dead_routing_key' => 'dead_key'
],
//订单支付队列
'order_pay' => [
'exchange_name' => 'order_change', //交换器名称
'exchange_type' => 'x-delayed-message', //交换机运行模式
'queue_name' => 'order_queue', //队列名称
'route_key' => 'order', //路由键,用于绑定队列与交换机
'consumer_tag' => 'order', //消费标签
'ttl' => 10000 //10s 毫秒为单位
]
];
2.新建RabbitMq.php
<?php
namespace app\controller;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPTable;
class RabbitMq
{
static private $instance;
static private $connection;
static private $channel;
static private $exchangeName = '';
static private $scene = '';
static private $config = [];
static private $dead_config = [];
/**
* RabbitMq constructor.
* @param $exchangeType
*/
private function __construct($scene)
{
// 取默认配置
$config = config('rabbitmq.AMQP');
//创建链接
self::$connection = new AMQPStreamConnection($config['host'], $config['port'], $config['user'], $config['password'], $config['vhost']);
self::$channel = self::$connection->channel();
if (!empty($scene)) {
self::$config = $info = config('rabbitmq.' . $scene);
self::$scene = $scene;
self::$exchangeName = $info['exchange_name'];
self::$dead_config = config('rabbitmq.dead_queue_info');
self::$channel->exchange_declare(
self::$exchangeName, //交换机名称
$info['exchange_type'], //路由类型
false, //don't check if a queue with the same name exists 是否检测同名队列
true, //the queue will not survive server restarts 是否开启队列持久化
false //the queue will be deleted once the channel is closed. 通道关闭后是否删除队列
);
}
}
/**
* 实例化
* @param string $exchangeType
* @return RabbitMq
*/
public static function instance($scene = '')
{
if (!self::$instance instanceof self) {
self::$instance = new self($scene);
}
return self::$instance;
}
/**
* 防止被外部复制
*/
private function __clone()
{
}
/**
* 发送(直接交换机)
* @param $routingKey
* @param string $data
* @param string $queue_name 队列名
* @param string $delay 是否延迟 1是 0否 (若延迟则开启死信队列)
*/
public function sendDirect($data = "", $delay = 0)
{
$arr = ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT];
if (empty($data)) $data = "Hello World!";
if ($delay) {
//延迟队列配合死信队列
//声明死信交换器
self::$channel->exchange_declare(self::$dead_config['dead_exc_name'], 'direct', false, false, false);
//声明死信队列
self::$channel->queue_declare(self::$dead_config['dead_queue_name'], false, true, false, false);
//死信队列绑定死信交换器
self::$channel->queue_bind(self::$dead_config['dead_queue_name'], self::$dead_config['dead_exc_name'], self::$dead_config['dead_routing_key']);
//
$args = new AMQPTable(['x-delayed-type' => 'direct']);
//过期时间
$arr['application_headers'] = new AMQPTable(['x-delay' => self::$config['ttl']]);
}
//设置队列名
self::$channel->queue_declare(self::$config['queue_name'], false, true, false, false, false, $args);
//队列绑定交换器
self::$channel->queue_bind(self::$config['queue_name'], self::$exchangeName, self::$config['route_key']);
//设置消息持久化以及过期时间
$msg = new AMQPMessage($data, $arr);
self::$channel->basic_publish($msg, self::$exchangeName, self::$config['route_key']);
echo "[x] Sent" . self::$config['route_key'] . ":$data \n";
}
/**
* 接收(直接交换机)
* @param \Closure $callback
* @param array $bindingKeys
*/
public function receiveDirect(\Closure $callback)
{
//随机生成队列名(生成后返回的是数组,只有第一个元素是队列名) 临时生成的,退出程序则消失
// list($queue_name,,) = $channel->queue_declare('', false, false, true, false);
// self::$channel->queue_declare(self::$config['queue_name'], false, true, true, false);
// foreach ($bindingKeys as $bindingKey) {
self::$channel->queue_bind(self::$config['queue_name'], self::$exchangeName, self::$config['route_key']);
// }
//一次只消费一条消息,未确认消费前不可消费其他消息
self::$channel->basic_qos(null, 1, null);
self::$channel->basic_consume(self::$config['queue_name'], "", false, true, false, false, $callback);
while (count(self::$channel->callbacks)) {
self::$channel->wait();
}
}
/**
* 销毁
*/
public function __destruct()
{
// TODO: Implement __destruct() method.
self::$channel->close();
self::$connection->close();
}
}
3.新建RabbitMqWork.php
<?php
namespace app\controller;
use app\controller\RabbitMq;
// RabbitMq 各个模式方法操作类
class RabbitMqWork
{
private $RabbitMq;
private $scene;
private $config;
//场景
public function __construct($scene = '')
{
$this->scene = $scene;
$this->config = config('rabbitmq.' . $scene);
$this->RabbitMq = RabbitMq::instance($scene);
}
/**
* 发送(直接交换机)
* @param $bindingKey
* @param $data
*/
public function sendDirect($data, $delay = 0)
{
$this->RabbitMq->sendDirect($data, $delay);
}
/**
* 接收(直接交换机)
* @param \Closure $callback
* @param array $bindingKeys
*/
public function receiveDirect(\Closure $callback, array $bindingKeys)
{
$this->RabbitMq->receiveDirect($callback, $bindingKeys);
}
}
4.业务代码
public function index()
{
$order_id = createFakeId();
$order_info = [
'product_type' => 'compute',
'order_amount' => '10000',
'pay_time' => '2022-09-02 18:14:00',
'config' => '4C4G',
'area' => '美国'
];
$redis = redis_connect();
$redis->setEx($order_id, 600, json_encode($order_info,JSON_UNESCAPED_UNICODE));
$rabbitmq = new RabbitMqWork('order_pay');
$rabbitmq->sendDirect($order_id, 1);
}
5.消费消息
注:tp中需使用自定义命令行(cli)进行消费
php think order & //加&可后台执行
<?php
declare(strict_types=1);
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use app\controller\RabbitMqWork;
class order extends Command
{
protected function configure()
{
// 指令配置
$this->setName('app\command\order')
->setDescription('the app\command\order command');
}
protected function execute(Input $input, Output $output)
{
// 指令输出
// $output->writeln('app\command\order');
$redis = redis_connect();
$info = config('rabbitmq.order_pay');
$rabbitmq = new RabbitMqWork('order_pay');
$callback = function ($msg) use ($redis) {
$rid = $msg->body;
$info = json_decode($redis->get($rid), 1);
if (!$info) debugLog('rabbitmq', '消息' . $rid . '已被消费');
//todo 执行业务逻辑
//执行结束,清除缓存
$redis->del($rid);
};
$rabbitmq->receiveDirect($callback, [$info['route_key']]);
}
}

浙公网安备 33010602011771号