如果客户端崩溃,任何人都知道在CLIENT_ACKNOWLEDGE模式下将重新传送哪些JMS消息?

时间:2010-06-07 16:45:19

标签: java-ee jms

规范说“确认消费消息会自动确认收到其会话已发送的所有消息” - 但我需要知道的是“交付”意味着什么。

例如,如果我调用consumer.receive()6次,然后在第3条消息上调用.acknowledge - 是(a)只有前3条消息是ack'd,还是(b)全部6条消息?

我真的希望它是一个选项a,即你重新发送你所谓的确认之后的消息将被重新传递,否则很难看到如果我的接收器进程崩溃之前你如何防止消息丢失有机会坚持并承认这些信息。但该规范的措辞使得目前尚不清楚。我得到了JMS规范的作者认为经纪人失败的印象,但没有花太多时间思考如何防止客户端失败:o(

由于 本

1 个答案:

答案 0 :(得分:4)

根据规范,选项(b)是正确的行为。如果您获得选项(a)并依赖它,则该应用程序将无法移植。

在下面的解释中,我指的是JMS规范 Version 1.1 April 12,2002

由于事实上它在会话级别运行时从消息对象调用了确认方法,因此存在一些混淆。因为它是一种消息方法,所以直观地说,人们可以在消息流中选择一个点来生成确认。

实际上发生的事情是消息确认正在会话级别驱动提交调用。由于会话一次只能激活一个事务,因此每个确认不会分隔消息流中的某个点,而是界定 in time 。 ack承诺现有的工作单元并开始下一个工作。在确认之前发送的消息必须包含在ack提交的工作单元中。

术语“已传递”通常被认为是API调用的完成,它从队列中删除消息并导致程序内存中的填充对象。实际上,当消息从队列中删除时,无论是否进入程序,都会认为该消息已被传递。例如,请考虑以下事件序列:

  1. 该应用会请求一条消息。
  2. 请求通过TCP套接字传递给服务器上的进程,该进程充当应用程序的代理。
  3. 代理向队列发出GET。
  4. 邮件被锁定在工作单元中并传递给代理进程。
  5. 代理进程尝试通过TCP套接字将消息传递给调用应用程序。如果此时连接断开,应用程序将不会看到该消息,但JMS提供程序认为它已被传递。检测到断开连接时,工作单元将被取消,消息将回滚到队列中,并且重新传递计数会递增。
  6. 应用程序收到消息。
  7. 应用程序确认消息。
  8. 代理进程接收提交调用并执行它。
  9. 在6&之间有一个窗口。 8,在此期间可以断开TCP套接字。在JMS提供者方面,它无法在步骤5中真正区分它和失败。无论哪种方式,消息都会回滚并在以后重新传递。但是在这种情况下,应用程序将看到该消息两次。该规范预测4.4.13中的这种情况:

      

    如果客户端在会话上提交工作之间发生故障,那么   提交方法返回,客户端无法确定事务是否   承诺或回滚。发生故障时存在相同的歧义   在非事务性发送PERSISTENT消息和返回之间   来自发送方法。

         

    由JMS应用程序来处理这种歧义。在某些情况下,这   可能会导致客户端产生功能上重复的消息。

         

    由于会话恢复而重新传递的消息不被视为a   重复的消息。

    在你的例子中你“调用consumer.receive()6次,然后在第3条消息上调用.acknowledge”并且观察到重新传递了消息4到6,可能的解释是a)六条消息是并非所有来自同一会话,或b)行为不符合规范。