使用Alpakka手动确认ActiveMQ消息

时间:2017-08-21 20:54:47

标签: java akka activemq akka-stream alpakka

我正在努力实现Akka Alpakka,以便在Java中使用和生成ActiveMQ队列。我可以成功地从队列中消耗,但我还没有能够实现应用程序级消息确认。

我的目标是使用队列中的消息并将它们发送给另一个actor进行处理。当该actor完成处理时,我希望它能够控制ActiveMQ中的消息确认。据推测,这可以通过向另一个可以进行确认的actor发送消息,在消息本身上调用确认函数或其他方式来完成。

在我的测试中,将2条消息放入AlpakkaTest队列,然后此代码尝试使用并确认它们。但是,我没有看到将ActiveMQ会话设置为CLIENT_ACKNOWLEDGE的方法,而且无论是否调用m.acknowledge();,我都没有看到任何行为上的差异。因此,我认为消息仍然是自动确认的。

有没有人知道为CLIENT_ACKNOWLEDGE配置ActiveMQ会话的可接受方式,并使用Alpakka在Java Akka系统中手动确认ActiveMQ消息?

相关的测试功能是:

ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://0.0.0.0:2999"); // An embedded broker running in the test.

Source<Message, NotUsed> jmsSource = JmsSource.create(
    JmsSourceSettings.create(connectionFactory)
        .withQueue("AlpakkaTest")
        .withBufferSize(2)
);

Materializer materializer = ActorMaterializer.create(system); // `system` is an ActorSystem passed to the function.

try {
    List<Message> messages = jmsSource
        .take(2)
        .runWith(Sink.seq(), materializer)
        .toCompletableFuture().get(4, TimeUnit.SECONDS);

    for(Message m:messages) {
        System.out.println("Found Message ID: " + m.getJMSMessageID());

        try {
            m.acknowledge();
        } catch(JMSException jmsException) {
            System.out.println("Acknowledgement Failed for Message ID: " + m.getJMSMessageID() + " (" + jmsException.getLocalizedMessage() + ")");
        }
    }
} catch (InterruptedException e1) {
    e1.printStackTrace();
} catch (ExecutionException e1) {
    e1.printStackTrace();
} catch (TimeoutException e1) {
    e1.printStackTrace();
} catch (JMSException e) {
    e.printStackTrace();
}

此代码打印:

Found Message ID: ID:jmstest-43178-1503343061195-1:26:1:1:1
Found Message ID: ID:jmstest-43178-1503343061195-1:27:1:1:1

2 个答案:

答案 0 :(得分:4)

更新:自Alpakka 0.15起,确认模式可在JMS连接器中配置。来自链接文档:

Source<Message, NotUsed> jmsSource = JmsSource.create(JmsSourceSettings
    .create(connectionFactory)
    .withQueue("test")
    .withAcknowledgeMode(AcknowledgeMode.ClientAcknowledge())
);

CompletionStage<List<String>> result = jmsSource
    .take(msgsIn.size())
    .map(message -> {
        String text = ((ActiveMQTextMessage)message).getText();
        message.acknowledge();
        return text;
    })
    .runWith(Sink.seq(), materializer);

从版本0.11开始,Alpakka的JMS连接器不支持应用程序级别的消息确认。 Alpakka使用Session模式here在内部创建CLIENT_ACKNOWLEDGE,并确认内部MessageListener中的每封邮件here。 API不会公开这些设置以覆盖。

有一个开放的ticket讨论了启用下游确认基于队列的源,但该票证已暂停一段时间。

目前,您无法阻止Alpakka在JMS级别确认消息。但是,这并不妨碍您向流添加一个阶段,该阶段将每个消息发送给演员进行处理,并将演员的回复用作背压信号。 Akka Streams documentation介绍了如何使用mapAsyncaskSink.actorRefWithAck的组合来执行此操作。例如,要使用前者:

Timeout askTimeout = Timeout.apply(4, TimeUnit.SECONDS);

jmsSource
    .mapAsync(2, msg -> ask(processorActor, msg, askTimeout))
    .runWith(Sink.seq(), materializer);

(旁注:在相关的Streamz项目中,最近打开了ticket以允许应用程序级别的确认.Streamz是旧的akka​​-camel模块的替代品,并且像Alpakka一样构建在Akka上Streams.Stream还有一个Java API,在Alpakka文档中是listed作为外部连接器。)

答案 1 :(得分:2)

查看Alpakka JmsSourceStage的源代码,它已经为您确认了每个传入消息(并且它的会话是Client Ack会话)。从我从源头上可以看出,没有允许你对消息进行确认的模式。

您可以查看Alpakka broken things的源代码。