我已经设置了一个在本地运行的独立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);
}
}
}
有人可以告诉我为什么它如此工作吗?我应该在客户端/服务器端使用哪种配置,以便如果消费者读取一条消息,它将把它从队列中删除?
答案 0 :(得分:1)
您不会在确认完成后提交会话,也不会在启用了自动提交确认的会话的情况下创建会话。因此,您应该执行以下任一操作:
session.commit()
的一个或多个调用之后,显式调用acknowledge()
sf.createSession(true,true)
或sf.createSession(false,true)
创建会话来启用隐式自动提交确认(第二个控制自动提交确认的布尔值)。请记住,启用对确认的自动提交功能时,在将确认刷新到代理之前,内部缓冲区需要达到特定大小。这样的批处理确认可以极大地提高某些大批量用例的性能。默认情况下,您需要确认价值1,048,576字节的消息,才能刷新缓冲区并将确认发送给代理。您可以通过在setAckBatchSize
实例上调用ServerLocator
或使用其他createSession
方法(例如sf.createSession(true, true, myAckBatchSize)
)来更改此缓冲区的大小。
如果未刷新确认缓冲区并且您的客户端崩溃,则当客户端返回时,相应的消息仍将在队列中。如果缓冲区尚未达到阈值,则在正常关闭使用者时仍将刷新该缓冲区。