当崩溃的核心客户端重新连接时,已确认的消息将重新发送

时间:2018-11-19 14:29:06

标签: java hornetq

我已经设置了一个在本地运行的独立HornetQ实例。为了进行测试,我使用HornetQ core API创建了一个使用者,该使用者每500毫秒会收到一条消息。

当我的客户端连接并从队列中读取所有消息时,我在使用方方面面临一种奇怪的行为,如果我强制关闭了该操作(没有正确关闭会话/连接),那么下次我再次启动该使用方时,它将读取队列中的旧消息。这是我的消费者示例:

// HornetQ消费者代码

   public void readMessage() {
    ClientSession session = null;
    try {
        if (sf != null) {
            session = sf.createSession(true, true);

            ClientConsumer messageConsumer = session.createConsumer(JMS_QUEUE_NAME);
            session.start();

            while (true) {
                ClientMessage messageReceived = messageConsumer.receive(1000);
                if (messageReceived != null && messageReceived.getStringProperty(MESSAGE_PROPERTY_NAME) != null) {
                    System.out.println("Received JMS TextMessage:" + messageReceived.getStringProperty(MESSAGE_PROPERTY_NAME));
                    messageReceived.acknowledge();
                }

                Thread.sleep(500);
            }
        }
    } catch (Exception e) {
        LOGGER.error("Error while adding message by producer.", e);
    } finally {
        try {
            session.close();
        } catch (HornetQException e) {
            LOGGER.error("Error while closing producer session,", e);
        }
    }
}

有人可以告诉我为什么它如此工作吗?我应该在客户端/服务器端使用哪种配置,以便如果消费者读取一条消息,它将把它从队列中删除?

1 个答案:

答案 0 :(得分:1)

您不会在确认完成后提交会话,也不会在启用了自动提交确认的会话的情况下创建会话。因此,您应该执行以下任一操作:

  • session.commit()的一个或多个调用之后,显式调用acknowledge()
  • 或者通过使用sf.createSession(true,true)sf.createSession(false,true)创建会话来启用隐式自动提交确认(第二个控制自动提交确认的布尔值)。

请记住,启用对确认的自动提交功能时,在将确认刷新到代理之前,内部缓冲区需要达到特定大小。这样的批处理确认可以极大地提高某些大批量用例的性能。默认情况下,您需要确认价值1,048,576字节的消息,才能刷新缓冲区并将确认发送给代理。您可以通过在setAckBatchSize实例上调用ServerLocator或使用其他createSession方法(例如sf.createSession(true, true, myAckBatchSize))来更改此缓冲区的大小。

如果未刷新确认缓冲区并且您的客户端崩溃,则当客户端返回时,相应的消息仍将在队列中。如果缓冲区尚未达到阈值,则在正常关闭使用者时仍将刷新该缓冲区。