假设我有经常填充一些数据的兔子队列(例如,用户提供了我们稍后需要分析的一些动作)。从30到50每秒添加新项目。 我需要的是创建一个工作程序,它将查看此队列并对该数据执行某些任务。我可以这样做:
class Worker
{
public function run()
{
$queue = new Queue('exchange', 'queue');
while (true)
{
$queue->processQueue();
}
}
}
然后在服务器上运行worker.php
,这似乎正在发挥作用。
但是我想知道如果没有数据可以继续,这个无限循环是否会给我的兔子实例增加额外负载?也许更好的方法是做一些事情:
class Worker
{
CONST IDLE = 5;
private $start = 0;
public function run()
{
$this->start = time();
$queue = new Queue('exchange', 'queue');
while (true)
{
$queue->processQueue();
//don't allow this worker to be working a lot
if (time() - $this->start >= 60 * 60 - self::IDLE)
{
break;
}
sleep(self::IDLE);
}
$queue->close();
}
}
所以我的工作不会持续从兔子那里提取数据但是会睡一会儿。经过一个小时的工作,它将停止工作,另一个工人实例将被crontab工作或其他东西调用?
答案 0 :(得分:3)
为了使用rabbitmq管理我的工作人员,我使用以下库:
https://github.com/php-amqplib/php-amqplib
然后我创建了一个定义我的工作者应该如何工作的类(包含所有rabbitmq逻辑),它给了我这样的东西:
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
abstract class QueueAMQPConsumer
{
protected $connection;
protected $debug;
protected $queueName;
protected $exchange;
public function __construct(AMQPStreamConnection $AMQPConnection, $queueName, $exchange = null)
{
$this->connection = $AMQPConnection;
$this->queueName = $queueName;
$this->exchange = $exchange;
}
public function run($debug = false)
{
$this->debug = $debug;
$channel = $this->connection->channel();
if ($this->exchange !== null) {
$channel->exchange_declare($this->exchange, "topic", false, true, false);
}
$channel->queue_declare($this->queueName, false, true, false, false);
if ($this->exchange !== null) {
$channel->queue_bind($this->queueName, $this->exchange);
}
$channel->basic_qos(null, 1, null);
$channel->basic_consume($this->queueName, '', false, false, false, false, [$this, 'callback']);
while (count($channel->callbacks)) {
$channel->wait();
}
$channel->close();
$this->connection->close();
}
final function callback(AMQPMessage $message)
{
$result = $this->process($message);
if (false === $result) {
$message->delivery_info['channel']->basic_nack($message->delivery_info['delivery_tag'], false, true);
} else {
$message->delivery_info['channel']->basic_ack($message-> delivery_info['delivery_tag']);
}
}
/**
* @param AMQPMessage $message
*
* @return bool
*/
abstract protected function process(AMQPMessage $message);
}
此类允许设置队列,交换(在本例中为主题),QoS(您可以自定义所有这些参数,这只是一个示例)等。
然后它将循环回调。这里的回调是抽象方法进程(...),它将在需要处理队列的不同工作者上实现。因此,“循环/收听”的责任在于频道:$channel->wait();
然后我将创建一个需要处理队列中消息的子类:
class MyWorker extends QueueAMQPConsumer
{
protected function process(AMQPMessage $message)
{
// .... process your message here
}
}
因此,工作人员将一直监听您的队列,并在他们到达队列时处理这些消息。
如果您的process(...)
返回的内容不是false,则会确认该消息。
你必须像这样启动你的课程:
$consumer = new MyWorker(....);
$consumer->run();