使用STOMP从ActiveMQ队列读取时的非阻塞事务

时间:2013-02-27 06:01:11

标签: php transactions activemq nonblocking stomp

我通过STOMP与ActiveMQ进行交互。我有一个发布消息的进程和一个订阅和处理消息的多个进程(大约10个并行实例)。

阅读完消息后,我想确保如果由于某种原因我的应用程序失败/崩溃,则消息不会丢失。很自然地,我转向了交易。不幸的是,我发现一旦消费者将消息作为交易的一部分阅读,所有以下消息都不会被发送给其他消费者,直到交易结束。

测试用例:abc队列有100条消息。如果我在两个不同的浏览器选项卡中激活以下代码,则第一个将在10秒内返回,第二个将在20秒内返回。

<?php
// Reader.php
$con = new Stomp("tcp://localhost:61613");
$con->connect();

$con->subscribe(
    "/queue/abc",
    array()
);

$tx = "tx3".microtime();
echo "TX:$tx<BR>";
$con->begin($tx);
$messages = array();
for ($i = 0; $i < 10; $i++) {
    $t = microtime(true);
    $msg = $con->readFrame();
    if (!$msg) {
        die("FAILED!");
    }
    $t = microtime(true)-$t; echo "readFrame() took $t MS to complete<BR>";
    array_push($messages, $msg);
    $con->ack($msg, $tx);
    sleep(1);
}
$con->abort($tx);

我有什么代码缺少的吗?有没有办法配置ActiveMQ(或发送标头),使事务从队列中删除项目,允许其他进程使用其他消息,如果事务失败或超时,将把项目重新放入?

PS:我考虑过为每个阅读过程创建另一个队列--DetentionQueue,但如果我有选择的话,我真的不愿意这样做。

1 个答案:

答案 0 :(得分:1)

您可能希望调整订阅的预取大小,以便ActiveMQ在客户端2有机会获取任何内容之前不会将队列上的消息发送到客户端1。默认情况下,它设置为1000,因此最好根据您的用例进行调整。

您可以通过订阅框架上的“activemq.prefetchSize = 1”标头设置预取大小。有关所有框架选项,请参阅ActiveMQ Stomp页面。