RabbitMQ:识别来自相同预取的消息

时间:2018-04-06 08:42:51

标签: rabbitmq prefetch

我的制作人看起来像这样:

$connection = new AMQPStreamConnection(
        $settings['amqp']['host'],
        $settings['amqp']['port'],
        $settings['amqp']['username'],
        $settings['amqp']['password']
);

$channel = $connection->channel();
$channel->queue_declare($settings['amqp']['queue'], false, true, false, false);

$msg = array();
$msg['time'] = time();

$msg = new AMQPMessage(json_encode($msg), array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT));
$channel->basic_publish($msg, '', $settings['amqp']['queue']);

$channel->close();
$connection->close();

我的消费者看起来像这样:

$connection = new AMQPStreamConnection(
        $settings['amqp']['host'],
        $settings['amqp']['port'],
        $settings['amqp']['username'],
        $settings['amqp']['password']
);

$channel = $connection->channel();
$channel->queue_declare($settings['amqp']['queue'], false, true, false, false);

$callback = function($message) {
        //echo $message->body . "\n";
        //echo $message->delivery_info['delivery_tag'] . "\n";
        var_dump($message) . "\n";
        $message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);
};

$channel->basic_qos(null, 30, null);
$channel->basic_consume($settings['amqp']['queue'], '', false, false, false, false, $callback);

try {
        while(count($channel->callbacks)) {
                $channel->wait();
        }
} catch (Exception $e){
        die();
}

由于我已将 basic_qos 设置为 null,30,null 我的消费者从群集中检索30封邮件的块。

我的目标是将这30个作为一个群体来识别。接下来的30人是不同的群体。

类似的东西:

注意:示例PHP + BASH !!!

$callback = function($message) {
        mkdir -p /tmp/$message->delivery_info['prefetch_group']
        echo $message->body > /tmp/$message->delivery_info['prefetch_group']/$message->delivery_info['delivery_tag']
};

最后。我将为每个块提供一个带有消息内容的目录。

当然 $ message-> delivery_info [' prefetch_group'] 不存在。而我在 $ message

中找不到任何有用的东西

只有在完成所有流程后,才能理想地为每个块发送basis_ack(30条消息)。

有什么想法来解决这个问题吗?

2 个答案:

答案 0 :(得分:0)

在收到另外30条消息之前,没有什么可以阻止您处理30条消息。

  • 在处理完第30条消息之后,等待发送确认
  • 务必将multiple标记设置为" true&#34 ;;这将确认收到第30条消息之前收到的所有消息
  • 显然,您需要按照收到的顺序保留邮件(它们一次来自经纪人)。这可以通过对DeliveryTag进行排序来完成。

作为一个警告,如果消息处理器失败/崩溃与第30条消息,并且你不承认其他29消息,那么你最终将把那些重新交付给你,所以这可能是你设计中要考虑的事情。

另请注意from the spec

  

服务器可以提前发送的数据少于客户端指定的预取窗口所允许的数据,但它不能发送更多数据。

答案 1 :(得分:0)

经过一些研究后,我做到了这一点。

使用 basic_get 代替 basic_consume

CODE NOT PROBED !!!想做个例子。

 16 $connection = new AMQPStreamConnection(
 17         $settings['amqp']['host'],
 18         $settings['amqp']['port'],
 19         $settings['amqp']['username'],
 20         $settings['amqp']['password']
 21 );
 22
 23 $channel = $connection->channel();
 24 $channel->queue_declare($settings['amqp']['queue'], false, true, false, false);
 25
 26 $messages = Array();
 27 for ($i=0; $i < 30; $i++) {
 28         $messages[] = $channel->basic_get($settings['amqp']['queue']);
 29 }
 30
 31 $now = time();
 32 foreach($messages as $message) {
 33         // DO WHATEVER YOU WANT WITH EACH MSG
 34         // system('mkdir -p /tmp/' . $now);
            // system('echo ' . $message->body . '> /tmp/' . $now . '/' . $message->delivery_info['delivery_tag']);
 35         echo $message->body . "\n";
 36 }
 37 
 38 // system('tar /tmp/' . $now . '.gz cvfz /tmp/' . $now);
 39
 40 foreach($messages as $message) {
 41         $channel->basic_ack($message->delivery_info['delivery_tag']);    
 42 }
 43
 44 $channel->close();
 45 $connection->close();

这只是一个POC。有必要:

  • 确保在推送至$ message之前有消息(第28行)
  • 控制许多可能的错误。
  • 以某种方式对消费者进行守护。

我需要详细了解 basic_get vs basic_consume ,但这个解决方案对我来说似乎不错。