0

什么是最佳实践,每秒通过 php 从队列中接收数据?我使用 ajax 查询来执行此操作,每秒调用一次 php 脚本。在那里,每次都会创建一个连接对象并声明一个队列。我第一次尝试将其保存在会话变量中,但是当我第二次调用 PHP 脚本时,我无法接收更多数据。当我调试通道对象时,我看到 is_open 是假的:

  protected' is_open' => boolean false 

这是我的基本 php 测试代码:

<?php


require_once __DIR__ . '/vendor/autoload.php';

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;



session_start(); # start session handling.

$id        = $_GET["uid"];
$connected = $_GET["connected"];

if (empty($id)) {
    $id = 0;
}
$queue = 'CyOS EV Queue ' . $id;

$reset = $_GET["reset"];

if ($reset === "true") {
    session_destroy();
    $_SESSION = array();
    echo "session destroyed";
    var_dump($_SESSION);
    exit;

}


$connection;
$channel;


if (!isset($_SESSION['coneccted'])) {

    $_SESSION['coneccted'] = true;

    $connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');


    $channel = $connection->channel();


    $channel->queue_declare($queue, false, false, false, false, false);

    $channel->queue_bind($queue, 'CyOS-EX');

    $_SESSION['connection'] = $connection;
    $_SESSION['channel']    = $channel;




} else {
    echo "already connected \n\r";
    $connection = $_SESSION['connection'];

    $channel = $_SESSION['channel'];

    var_dump($_SESSION);

}

$test = new AMQPMessage();

while ($i < 10) {

echo "try to get data from " . $queue . "\n\r";
$test = $channel->basic_get($queue, true);

$i++;
if (isset($test)) {
    echo "received data";
    break;

   }
 }
echo $test->body;

当我每次调用脚本时初始化连接和通道时,它就会起作用。

4

1 回答 1

2

我想你关心的是这些:

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare($queue, false, false, false, false, false);
$channel->queue_bind($queue, 'CyOS-EX');

让我们看看这里发生了什么:

  1. 连接到 RabbitMQ 服务器。这就像连接到数据库、内存缓存或任何其他外部进程,并且需要在每个 PHP 请求中发生。您不能将连接存储在会话中,因为它不是数据,它是一个活动资源,当 PHP 退出时将关闭。
  2. 请求连接上的默认通道。这实际上只是连接代码的一部分,不应消耗任何大量时间或资源。
  3. 声明队列。这将检查队列是否已经存在,如果存在,则什么也不做。另一方面,如果您知道队列存在(因为它是在管理界面中创建的永久队列,或者您确定另一个进程将创建它),您可以跳过此行。
  4. 将队列绑定到交换机。这是队列设置的一部分;如果队列不存在且尚未绑定,则在此行运行之前,其中将没有任何内容可消耗。与上一步一样,如果您知道它发生在其他地方,则可以跳过它。

避免重新连接(第 1 步和第 2 步)的正常方法是让消费者在后台运行,例如使用supervisord启动命令行 PHP 脚本,该脚本在消息进入时连续运行处理消息。但是,这不会如果您需要在数据出现在队列中后将数据返回到浏览器,则可以使用。

每次轮询和创建新 PHP 进程的常见替代方法包括:

  • 长轮询,AJAX 调用等待直到它有东西要返回,而不是返回一个空的结果。
  • 流式传输响应(将每个结果从 PHP 回显到浏览器,但不会结束该过程)。
  • WebSockets(我在 PHP 中没有看到一个好的实现,但可能有一个)。

正如我所说,这些并不是 RabbitMQ 特有的,而是适用于您等待数据库、文件、远程服务等发生某些事情的任何时候。

于 2018-03-15T13:11:53.210 回答