前言
此案例采用 pub/sub订阅者模式,生成一次,多次消费
由于项目越来越大,尤其在订单这一块做了很多活动,这时候就很难维护,需要把每一块解耦,作为消费者
减少用户的等待时间,避免出现相关业务失败问题
即使相关业务失败,也不会影响主流程
依赖
- php 7.2+
- php-sockets 、mbstring 扩展
- Erlang 语言
- 基于Erlang开发的rabbitMQ应用
- laravel 6+
安装
安装Erlang 及rabiitMq: https://www.jianshu.com/p/bc6da5db58ca
生产者
# 生成一个命令
user> php artisan make:command SendMqCommand
# 在 app\console\Commands\SendMqCommand中编辑以下
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Exchange\AMQPExchangeType;
use PhpAmqpLib\Message\AMQPMessage;
class SendMqCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'send_mq';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
/**
* 发送消息
*/
$exchangeName = 'order3';
$routeKey = 'orderCreate3';
$message = json_encode(['order_id' => 50]);
/*注意*/这里不需要交换机绑定队列,否则只能生产一条消息,只能被多个队列其中一个消费
$connection = new AMQPStreamConnection(
'localhost',
'5672',
'guest',
'guest',
'/'
);
$channel = $connection->channel();
$channel->exchange_declare($exchangeName, AMQPExchangeType::FANOUT, false, true, false);
$message = new AMQPMessage($message, array('content_type' => 'text/json'));
$channel->basic_publish($message, $exchangeName);
$channel->close();
$connection->close();
}
}
消费者1
#生成一个消费者命令
user > php artisan make:command OrderCreateCommand
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Exchange\AMQPExchangeType;
class OrderCreateCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'order_create1';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
/**
* 接收消息
*/
$exchangeName = 'order3';
$routeKey = 'orderCreate3';
$queue = 'order_deal3';
$consumerTag = 'consumer3';
$connection = new AMQPStreamConnection(
'localhost',
'5672',
'guest',
'guest',
'/'
);
$channel = $connection->channel();
$channel->queue_declare($queue, false, true, false, false);
$channel->exchange_declare($exchangeName, AMQPExchangeType::FANOUT, false, true, false);
$channel->queue_bind($queue, $exchangeName);
$channel->basic_consume($queue, $consumerTag, false, false, false, false, function ($message)
{
echo "\n--------\n";
echo $message->body;
echo "\n--------\n";
$message->ack();
// Send a message with the string "quit" to cancel the consumer.
if ($message->body === 'quit') {
$message->getChannel()->basic_cancel($message->getConsumerTag());
}
});
register_shutdown_function(function ($channel, $connection)
{
$channel->close();
$connection->close();
}, $channel, $connection);
while ($channel ->is_consuming()) {
$channel->wait();
}
}
}
消费者2
只需要在消费者1的命令基础上,增加一个命令文件,把其中代码$queue变量改为不重复的队列名称如 order_deal4
操作
# 启动消费1、2,监听,订阅订单创建的消息
user > php artisan order_create1
user > php artisan order_create2
# 生成者负责发送订单创建消息
user > php artisan send_msg