php-amqplib
在项目目录下运行composer require php-amqplib/php-amqplib
RabbitMQ
的基本操作
namespace App\Components;
use App\Components\BaseComponent;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
class RmqClientComponent extends BaseComponent
{
/**
* @var object $instance 单例对象
*/
private static $instance = null;
/**
* @var object $connection 队列连接对象
*/
private $connection = null;
/**
* @var object $channel 队列通道对象
*/
private $channel = null;
/**
* @var object $message 队列消息对象
*/
private $message = null;
/**
* 构造函数
*
*/
private function __construct()
{
$this->connection = new AMQPStreamConnection(
config('database.rabbitmq.host'),
config('database.rabbitmq.port'),
config('database.rabbitmq.user'),
config('database.rabbitmq.pass'),
config('database.rabbitmq.vhost')
);
$this->channel = $this->connection->channel();
$this->message = new AMQPMessage('', ['content_type' => 'json', 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]);
}
/**
* 克隆函数
*
* 私有防克隆
*/
private function __clone()
{
}
/**
* 析构函数
*/
public function __destruct()
{
$this->channel->close();
$this->connection->close();
self::$instance = null;
}
/**
* 单例实例化入口
*/
public static function getInstance()
{
if (!self::$instance instanceof self) {
self::$instance = new self();
}
return self::$instance;
}
/**
* 消息入队列
*
* @param string $strExchange 交换机名称
* @param string $strQueue 队列名称
* @param array $aBody 消息内容
* @param string $strType 路由类型
*
* @return array $aRes 标准输出
*/
public function add($strExchange, $strQueue, $aBody, $strType = 'direct')
{
// 参数校验
$objValidator = \Validator::make(
[
'exchange' => $strExchange,
'queue' => $strQueue,
'body' => $aBody,
'type' => $strType,
],
[
'exchange' => 'required|string',
'queue' => 'required|string',
'body' => 'required|array',
'type' => 'required|string',
]
);
if ($objValidator->fails()) {
return self::error($objValidator->errors()->first());
}
try {
// 声明交换机
// 默认精准推送,不检测同名交换机,持久化,不自动删除交换机
$this->channel->exchange_declare($strExchange, $strType, false, true, false);
// 声明队列
// 不检测同名队列,持久化,不允许其他队列访问,不自动删除队列
$this->channel->queue_declare($strQueue, false, true, false, false);
// 绑定队列和交换机,用队列名作routingKey
$this->channel->queue_bind($strQueue, $strExchange, $strQueue);
// 设备消息体
$this->message->setBody(json_encode($aBody));
// 推送信息
$this->channel->basic_publish($this->message, $strExchange, $strQueue);
} catch (Exception $e) {
return self::error($e->getMessage());
}
return self::success();
}
/**
* 从队列读取消息
*
* @param string $strQueue 队列名称
* @param boolean $bForceDelete 是否取后即删
*
* @return array $aRes 标准输出
* $aRes['data'] => message object
*/
public function get($strQueue, $bForceDelete = false)
{
// 参数校验
$objValidator = \Validator::make(
[
'queue' => $strQueue,
],
[
'queue' => 'required|string',
]
);
if ($objValidator->fails()) {
return self::error($objValidator->errors()->first());
}
try {
// 取数据
$aValue = [];
// 声明队列
// 不检测同名队列,持久化,不允许其他队列访问,不自动删除队列
$this->channel->queue_declare($strQueue, false, true, false, false);
$objMessage = $this->channel->basic_get($strQueue);
if ($objMessage && $bForceDelete) {
// 回复确认信息
$this->channel->basic_ack($objMessage->delivery_info['delivery_tag']);
}
} catch (Exception $e) {
return self::error($e->getMessage());
}
return self::success($objMessage);
}
/**
* 回复响应消息
*
* @param int $nTag 消息传递标签
*
* @return array $aRes 标准输出
*/
public function ack($nTag)
{
try {
$this->channel->basic_ack($nTag);
} catch (Exception $e) {
return self::error($e->getMessage());
}
return self::success();
}
}
artisan
命令
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Components\RmqClientComponent;
use App\Components\EmailComponent;
class AsynSendEmail extends Command
{
protected $signature = 'send:AsynSendEmail';
protected $description = '异步发送邮件';
public function handle()
{
while (true) {
$objRabbitMQ = RmqClientComponent::getInstance();
$strQueue = 'test_send_mail';
$aMqMessage = $objRabbitMQ->get($strQueue, true);
$objMqData = $aMqMessage['data'];
if ($objMqData) {
$strBody = $objMqData->body;
$aMail = json_decode($strBody, true);
$aResult = EmailComponent::sendEmail($aEmail);
if ($aResult['status_code'] != 200) {
$strExchange = 'test_exchange';
$objRabbitMQ->add($strExchange, $strQueue, $aMail, $strType = 'direct');
}
}
}
}
}
public static function sendEmail($aEmail)
{
// 参数校验
$objValidator = \Validator::make(
[
'email' => $aEmail,
],
[
'email' => 'required|array',
'email.mail_to' => 'required|string',
'email.mail_title' => 'required|string',
'email.mail_cc' => 'string',
'email.mail_files' => 'string',
'email.mail_id' => 'integer',
]
);
if ($objValidator->fails()) {
return self::error($objValidator->errors()->first());
}
$objRabbitMQ = RmqClientComponent::getInstance();
$strExchange = 'test_exchange';
$strQueue = 'test_send_mail';
$aBody=$aEmail;
$aMqResult= $objRabbitMQ->add($strExchange, $strQueue, $aBody, $strType = 'direct');
if($aMqResult['status']=='true'){
return self::success();
}else{
return self::error($aMqResult['msg']);
}
}
防止 artisan
命令的进程挂掉
ps axu|grep "php artisan send:AsynSendEmail"|grep -v "grep"|wc -l;
artisan
命令