>The environment for this article is Ubuntu 20.04, nginx1.0 8,PHP7.3,RabbitMq3.9\
>If you don't understand, you can comment or contact me at email: owen@owenzhang.com \
>The copyright belongs to Owen Zhang. For commercial reprint, please contact Owen Zhang for authorization. For non-commercial reprint, please indicate the source.
Project code
[https://gitee.com/owenzhang24/tp5](https://gitee.com/owenzhang24/tp5)
Queue notes
1: Listing queues
If you want to view the Rabbitmq queue and want to know how many messages exist in it, you (as a privileged user) can use the rabbitmqctl tool:
rabbitmqctl list_queues.
In Windows, omit sudo:
rabbitmqctl.bat list_queues
2: Work queue
We found that even if we kill a worker process with CTRL+C, the message will not be lost. When the worker hangs up, all unresponsive messages will be sent again.
An easy mistake to make is to forget basic_ack, the consequences are serious. Messages will be re sent after your program exits. If it cannot release unresponsive messages, RabbitMQ will occupy more and more memory.
To eliminate this error, you can use the rabbitmqctl command to output messages_unacknowledged field:
``` $ sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged ```
Run in the window system and remove sudo:
``` $ rabbitmqctl.bat list_queues name messages_ready messages_unacknowledged ```
3: rabbitmqctl can list all switches on the server:
``` $ sudo rabbitmqctl list_exchanges ```
Some of this list are called amq* Heat exchanger. These are created by default, but you don't need to use them yet.
4: List all existing bindings
``` rabbitmqctl list_bindings ```
5: If you want to save the log to a file, just open the console and enter: ([receive_logs.php]( https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2Frabbitmq%2Frabbitmq -tutorials%2Fblob%2Fmaster%2Fphp%2Freceive_ logs. PHP (source code)
``` $ php receive_logs.php > logs_from_rabbit.log ```
If you want all log information to be output to the screen, open a new terminal and enter:
``` $ php receive_logs_direct.php info warning erro # => [*] Waiting for logs. To exit press CTRL+C ```
If you want to trigger an error level log, you only need to enter:
``` $ php emit_log_direct.php error "Run. Run. Or it will explode." # => [x] Sent 'error':'Run. Run. Or it will explode.' ```
Queue installation
First: install RabbitMq environment
[rabbitmq installation and startup in windows environment]( https://my.oschina.net/owenzhang24/blog/5051652)
[https://my.oschina.net/owenzhang24/blog/5051652](https://my.oschina.net/owenzhang24/blog/5051652)
Second:
``` composer require php-amqplib/php-amqplib ```
Third: Code Class
1. Basic classes implemented by rabbitmq: application / common / lib / classes / rabbitmq / rabbitmq php
2. rabbitMq class for external call: application / common / lib / classes / rabbitmqwork php
3. Test the method of sending messages to rabbitMq: application / index / controller / index php
4. Add php think command to receive messages in rabbitMq: application / common / command / * php
Fourth: instructions for use
1. call RabbitMqWork. directly in your own way when sending messages. Just a few message sending methods in the PHP class.
2. The classes under application / common / command / are all classes that implement the addition of php think command. Set the command name in setName() in the configure method, and the execute() method is to receive the message in rabbitMq, and at the same time in application / command Add the set command name and the corresponding command directory address to return in PHP.
3. Contribution documents
4. [RabbitMQ Chinese document - PHP version]( https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fxiaoxiami.gitbook.io%2Frabbitmq_into_chinese_php%2F). [ https://xiaoxiami.gitbook.io/rabbitmq_into_chinese_php/ ]( https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fxiaoxiami.gitbook.io%2Frabbitmq_into_chinese_php%2F)
5. [RabbitMQ official document]( https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.rabbitmq.com%2Fgetstarted.html). [ https://www.rabbitmq.com/getstarted.html ]( https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.rabbitmq.com%2Fgetstarted.html)
Fifth: source code
application/common/lib/classes/rabbitmq/RabbitMq.php ``` <?php //Basic class of rabbitMq implementation namespace app\common\lib\classes\rabbitmq; use PhpAmqpLib\Connection\AMQPStreamConnection; use PhpAmqpLib\Message\AMQPMessage; class RabbitMq { static private $instance; static private $connection; static private $channel; const DIRECT = 'direct'; const TOPIC = 'topic'; const HEADERS = 'headers'; const FANOUT = 'fanout'; static private $exchangeNames = [ self::DIRECT => 'direct_exchange', self::TOPIC => 'topic_exchange', self::HEADERS => 'headers_exchange', self::FANOUT => 'fanout_exchange', ]; const SEVERITYS = [ 'info', 'warning', 'error' ]; static private $exchangeName = ''; /** * RabbitMq constructor. * @param $exchangeType */ private function __construct($exchangeType) { self::$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest'); self::$channel = self::$connection->channel(); if (!empty($exchangeType)) { self::$exchangeName = self::$exchangeNames[$exchangeType]; self::$channel->exchange_declare( self::$exchangeName, //Switch name $exchangeType, //Routing 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. Delete queue after channel is closed ); } } /** * instantiation * @param string $exchangeType * @return RabbitMq */ public static function instance($exchangeType = '') { if (!self::$instance instanceof self) { self::$instance = new self($exchangeType); } return self::$instance; } /** * Prevent external replication */ private function __clone() { } /** * Simple sending */ public function send() { self::$channel->queue_declare('hello', false, false, false); $msg = new AMQPMessage('Hello World!'); self::$channel->basic_publish($msg, '', 'hello'); echo "[X] Sent 'Hello World!'\n"; } /** * Simple reception * @param $queueName * @param $callback */ public function receive($callback) { self::$channel->queue_declare('hello', false, false, false, true); echo "[*] Waiting for messages. To exit press CTRL+C\n"; self::$channel->basic_consume('hello', '', false, true, false, false, $callback); while (count(self::$channel->callbacks)) { self::$channel->wait(); } } /** * Add work queue * @param string $data */ public function addTask($data = '') { self::$channel->queue_declare('task_queue', false, true, false, true); if (empty($data)) $data = 'Hello World!'; $msg = new AMQPMessage( $data, array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT) ); self::$channel->basic_publish($msg, '', 'task_queue'); echo "[x] Sent $data \n"; } /** * Execute work queue * @param $callback */ public function workTask($callback) { self::$channel->queue_declare('task_queue', false, true, false, true); echo ' [*] Waiting for messages. To exit press CTRL+C', "\n"; self::$channel->basic_qos(null, 1, null); self::$channel->basic_consume('task_queue', '', false, false, false, false, $callback); while (count(self::$channel->callbacks)) { self::$channel->wait(); } } /** * release * @param string $data */ public function sendQueue($data = '') { if (empty($data)) $data = 'info:Hello World!'; $msg = new AMQPMessage($data); self::$channel->basic_publish($msg, self::$exchangeName); echo "[x] Sent $data \n"; } /** * subscribe * @param $callback */ public function subscribeQueue($callback) { list($queue_name, ,) = self::$channel->queue_declare( "", //Queue name false, //don't check if a queue with the same name exists true, //the queue will not survive server restarts true, //the queue might be accessed by other channels false //the queue will be deleted once the channel is closed. Delete queue after channel is closed ); self::$channel->queue_bind($queue_name, self::$exchangeName); echo "[*] Waiting for logs. To exit press CTRL+C \n"; self::$channel->basic_consume($queue_name, '', false, true, false, false, $callback); while (count(self::$channel->callbacks)) { self::$channel->wait(); } } /** * Send (direct switch) * @param $routingKey * @param string $data */ public function sendDirect($routingKey, $data = '') { if (empty($data)) $data = "Hello World!"; $msg = new AMQPMessage($data); self::$channel->basic_publish($msg, self::$exchangeName, $routingKey); echo "[x] Sent $routingKey:$data \n"; } /** * Receive (direct switch) * @param \Closure $callback * @param array $bindingKeys */ public function receiveDirect(\Closure $callback, array $bindingKeys) { list($queue_namme, ,) = self::$channel->queue_declare('', false, true, true, false); foreach ($bindingKeys as $bindingKey) { self::$channel->queue_bind($queue_namme, self::$exchangeName, $bindingKey); } echo "[x] Waiting for logs. To exit press CTRL+C \n"; self::$channel->basic_consume($queue_namme, '', false, true, false, false, $callback); while (count(self::$channel->callbacks)) { self::$channel->wait(); } } /** * Send (theme switch) * @param $routingKey * @param string $data */ public function sendTopic($routingKey, $data = '') { if (empty($data)) $data = "Hello World!"; $msg = new AMQPMessage($data); self::$channel->basic_publish($msg, self::$exchangeName, $routingKey); echo " [x] Sent ", $routingKey, ':', $data, " \n"; } /** * Receive (theme switch) * @param \Closure $callback * @param array $bindingKeys */ public function receiveTopic(\Closure $callback, array $bindingKeys) { list($queueName, ,) = self::$channel->queue_declare("", false, true, true, false); foreach ($bindingKeys as $bindingKey) { self::$channel->queue_bind($queueName, self::$exchangeName, $bindingKey); } echo ' [*] Waiting for logs. To exit press CTRL+C', "\n"; self::$channel->basic_consume($queueName, '', false, true, false, false, $callback); while (count(self::$channel->callbacks)) { self::$channel->wait(); } } /** * Destroy */ public function __destruct() { // TODO: Implement __destruct() method. self::$channel->close(); self::$connection->close(); } } ``` \ application/common/lib/classes/RabbitMqWork.php ``` <?php //rabbitMq class for external calls namespace app\common\lib\classes; use app\common\lib\classes\rabbitmq\RabbitMq; class RabbitMqWork { private $RabbitMq; public function __construct($exchageType = '') { $this->RabbitMq = RabbitMq::instance($exchageType); } /** * Send (normal) */ public function send() { $this->RabbitMq->send(); } /** * Receiving (normal) * @param $callback */ public function receive($callback) { $this->RabbitMq->receive($callback); } /** * Send (work queue) * @param $data */ public function addTask($data) { $this->RabbitMq->addTask($data); } /** * Receive (work queue) * @param $callback */ public function workTask($callback) { $this->RabbitMq->workTask($callback); } /** * Release (sector switch) * @param $data */ public function sendQueue($data) { $this->RabbitMq->sendQueue($data); } /** * Subscription (sector switch) * @param $callback */ public function subscribeQueue($callback) { $this->RabbitMq->subscribeQueue($callback); } /** * Send (direct switch) * @param $bindingKey * @param $data */ public function sendDirect($routingKey, $data) { $this->RabbitMq->sendDirect($routingKey, $data); } /** * Receive (direct switch) * @param \Closure $callback * @param array $bindingKeys */ public function receiveDirect(\Closure $callback, array $bindingKeys) { $this->RabbitMq->receiveDirect($callback, $bindingKeys); } /** * Send (theme switch) * @param $routingKey * @param $data */ public function sendTopic($routingKey, $data) { $this->RabbitMq->sendTopic($routingKey, $data); } /** * Receive (theme switch) * @param \Closure $callback * @param array $bindingKeys */ public function receiveTopic(\Closure $callback, array $bindingKeys) { $this->RabbitMq->receiveTopic($callback, $bindingKeys); } } ``` \ application/index/controller/Index.php ``` <?php namespace app\index\controller; use app\common\lib\classes\rabbitmq\RabbitMq; use app\common\lib\classes\RabbitMqWork; use app\polymerize\tool\module\es\SearchBlog; use app\polymerize\tool\module\es\SyncBlog; use think\Collection; class Index extends Collection { public function index() { // $this->send(); // $this->addTask(); // $this->sendQueue(); // $this->sendDirect(); $this->sendTopic(); var_dump(11); die(); } public function searchBlog() { // $id=1; // $res = SyncBlog::getInstance()->syncBlog($id); $search='11'; $res = SearchBlog::getInstance()->searchBlog($search, 1, 100); var_dump($res); die(); var_dump(1111); die(); } /** * Send (normal) */ public function send() { $RabbitMqWork = new RabbitMqWork(); $RabbitMqWork->send(); } /** * Send (work queue) */ public function addTask() { $data = input('data', 'This is work task!'); $RabbitMqWork = new RabbitMqWork(); $RabbitMqWork->addTask($data); } /** * Send (sector switch) */ public function sendQueue() { $data = input('data', 'This is send queue1'); $RabbitMqWork = new RabbitMqWork(RabbitMq::FANOUT); $RabbitMqWork->sendQueue($data); } /** * Send (direct switch) */ public function sendDirect() { $data = input('data', 'Hello World!'); $routingKey = input('routingKey', 'info'); $RabbitMqWork = new RabbitMqWork(RabbitMq::DIRECT); $RabbitMqWork->sendDirect($routingKey, $data); } /** * Send (theme switch) */ public function sendTopic() { $data = input('data', 'Hello World!'); $routingKey = input('routingKey', 'lazy.boy'); $RabbitMqWork = new RabbitMqWork(RabbitMq::TOPIC); $RabbitMqWork->sendTopic($routingKey, $data); } } ``` application/command.php ``` <?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- // | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- return [ 'simpleMq' => 'application\command\SimpleWork', 'workQueue' => 'application\command\WorkQueue', 'sendQueue' => 'application\command\SendQueue', 'directQueue' => 'application\command\DirectQueue', 'topicQueue' => 'application\command\TopicQueue', ]; ``` application/common/command/*.php application/command/DirectQueue.php ``` <?php /** * Receive (direct switch) * @param \Closure $callback * @param array $bindingKeys */ namespace app\command; use app\common\lib\classes\rabbitmq\RabbitMq; use app\common\lib\classes\RabbitMqWork; use think\console\Command; use think\console\Input; use think\console\Output; class DirectQueue extends Command { protected function configure() { parent::configure(); // TODO: Change the autogenerated stub $this->setName('directQueue'); } protected function execute(Input $input, Output $output) { $RabbitMqWork = new RabbitMqWork(RabbitMq::DIRECT); $callback = function ($msg){ echo "[x] ".$msg->delivery_info['routing_key'].":$msg->body \n"; }; $RabbitMqWork->receiveDirect($callback,RabbitMq::SEVERITYS); } } ``` application/command/SendQueue.php ``` <?php /** * Subscription (sector switch) * @param $callback */ namespace app\command; use app\common\lib\classes\rabbitmq\RabbitMq; use app\common\lib\classes\RabbitMqWork; use think\console\Command; use think\console\Input; use think\console\Output; use think\Log; class SendQueue extends Command { protected function configure() { parent::configure(); // TODO: Change the autogenerated stub $this->setName('sendQueue'); } protected function execute(Input $input, Output $output) { $RabbitMqWork = new RabbitMqWork(RabbitMq::FANOUT); $callback = function ($msg) { echo 'Receive:'; echo "Msg:$msg->body \n"; \Log::error("Msg:$msg->body"); }; $RabbitMqWork->subscribeQueue($callback); } } ``` application/command/SimpleWork.php ``` <?php /** * Receiving (normal) * @param $callback */ namespace app\command; use app\common\lib\classes\RabbitMqWork; use think\console\Command; use think\console\Input; use think\console\Output; use think\Log; class SimpleWork extends Command { protected function configure() { parent::configure(); // TODO: Change the autogenerated stub $this->setName('simpleMq'); } protected function execute(Input $input, Output $output) { $RabbitMqWork= new RabbitMqWork(); $callback = function ($msg){ echo 'Receive:'; $queueName = $msg->delivery_info['routing_key']; $msgData = $msg->body; $isAck = true; echo 'Msg:'.$msgData."\n"; echo 'QueueName:'.$queueName."\n"; if($isAck) { $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']); } }; $RabbitMqWork->receive($callback); } } ``` application/command/TopicQueue.php ``` <?php /** * Receive (theme switch) * @param \Closure $callback * @param array $bindingKeys */ namespace app\command; use app\common\lib\classes\rabbitmq\RabbitMq; use app\common\lib\classes\RabbitMqWork; use think\console\Command; use think\console\Input; use think\console\Output; class TopicQueue extends Command { protected function configure() { parent::configure(); // TODO: Change the autogenerated stub $this->setName('topicQueue'); } protected function execute(Input $input, Output $output) { $RabbitMqWork = new RabbitMqWork(RabbitMq::TOPIC); $callback = function ($msg){ echo ' [x] ',$msg->delivery_info['routing_key'], ':', $msg->body, "\n"; }; $bindingKeys = [ '*.orange.*', '*.*.rabbit', 'lazy.#' ]; $RabbitMqWork->receiveTopic($callback,$bindingKeys); } } ``` application/command/WorkQueue.php ``` <?php /** * Receive (work queue) * @param $callback */ namespace app\command; use app\common\lib\classes\RabbitMqWork; use think\console\Command; use think\console\Input; use think\console\Output; class WorkQueue extends Command { protected function configure() { parent::configure(); // TODO: Change the autogenerated stub $this->setName('workQueue'); } protected function execute(Input $input, Output $output) { $RabbitMqWork = new RabbitMqWork(); $callback = function ($msg){ echo " [x] Received ", $msg->body, "\n"; sleep(substr_count($msg->body, '.')); echo " [x] Done", "\n"; $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']); }; $RabbitMqWork->workTask($callback); } } ``` ## Buy me a cup of coffee :)