Laravel工作佇列
安裝元件
~ composer require php-amqplib/php-amqplib
建立一個初始化抽象類
InitAbstract
對連線及通用的定義進行簡單的封裝
<?php
/**
* User: Loki.Q
* Date: 2020/5/12
* Time: 11:43
*/
namespace App\Services\RabbitMQ;
use PhpAmqpLib\Connection\AMQPStreamConnection;
/**
* Class InitAbstract
* @package App\Services\RabbitMQ
*/
abstract class InitAbstract
{
/**
* @var AMQPStreamConnection
*/
protected $connection;
/**
* HOST地址
* @var string
*/
private $host = '127.0.0.1';
/**
* 埠
* @var string
*/
private $port = '5672';
/**
* 賬號
* @var string
*/
private $user = 'test001';
/**
* 密碼
* @var string
*/
private $passwd = 'test001';
/**
* vhost
* @var string
*/
private $vhost = 'hello';
/**
* 佇列名稱
* @var string
*/
protected $queueName = 'test_queue';
/**
* 連線RabbitMQ
* InitAbstract constructor.
*/
public function __construct()
{
$this->connection = new AMQPStreamConnection(
$this->host,
$this->port,
$this->user,
$this->passwd,
$this->vhost
);
}
/**
* 定義頻道
* @return \PhpAmqpLib\Channel\AMQPChannel
*/
protected function channel()
{
$channel = $this->connection->channel();
/**
* 為了不讓佇列消失,需要把佇列宣告為持久化(durable)。
* 為此我們通過queue_declare的第三引數為 true
*/
$channel->queue_declare(
$this->queueName, false, true, false, false
);
return $channel;
}
}
定義一個生產者類
Producer
<?php
/**
* User: Loki.Q
* Date: 2020/5/12
* Time: 11:51
*/
namespace App\Services\RabbitMQ;
use PhpAmqpLib\Message\AMQPMessage;
/**
* Class Producer
* @package App\Services\RabbitMQ
*/
class Producer extends InitAbstract
{
/**
* 釋出訊息
*/
public function push()
{
$channel = $this->channel();
$data = 'this is message';
$msg = new AMQPMessage($data, [
//訊息持久化
'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT
]);
$channel->basic_publish(
$msg, '', $this->queueName
);
echo " [x] Sent ", $data, "\n";
$channel->close();
$this->connection->close();
}
}
定義消費者類
Consumer
<?php
/**
* User: Loki.Q
* Date: 2020/5/12
* Time: 13:44
*/
namespace App\Services\RabbitMQ;
/**
* Class Consumer
* @package App\Services\RabbitMQ
*/
class Consumer extends InitAbstract
{
/**
* @throws \ErrorException
*/
public function wait()
{
$channel = $this->channel();
echo " [*] Waiting for messages. To exit press CTRL+C\n";
$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']);
};
/**
* 這時因為RabbitMQ只管分發進入佇列的訊息,不會關心有多少消費者(consumer)沒有作出響應。
* 它盲目的把第n-th條訊息發給第n-th個消費者。
* 我們可以使用basic.qos方法,並設定prefetch_count=1。
* 訊息並且作出了響應。
* 這樣,RabbitMQ就會把訊息分發給下一個空閒的工作者(worker)。
*/
$channel->basic_qos(null, 1, null);
$channel->basic_consume(
$this->queueName, '', false, false, false, false, $callback
);
while (count($channel->callbacks)) {
$channel->wait();
}
$channel->close();
$this->connection->close();
}
}
在
routes/console.php
中定義命令監聽消費
Artisan::command('queue', function (\App\Services\RabbitMQ\Consumer $consumer) {
$consumer->wait();
})->describe('rabbitmq queue');
定義一個
Controller
來執行生產
<?php
/**
* User: Loki.Q
* Date: 2020/5/12
* Time: 13:37
*/
namespace App\Http\Controllers;
use App\Services\RabbitMQ\Producer;
class ProducerController extends Controller
{
public function handle(Producer $producer)
{
return $producer->push();
}
}
定義好路由後,執行生產
~ curl http://xx.test/producer/push
[x] Sent this is message
結果
~ php artisan queue
[*] Waiting for messages. To exit press CTRL+C
[x] Received this is message
[x] Done
[x] Received this is message
[x] Done
[x] Received this is message
[x] Done
本作品採用《CC 協議》,轉載必須註明作者和本文連結