我可以将IBM MQ消息标记为脏吗?

时间:2017-05-23 13:44:16

标签: ibm-mq

我确实有以下(多线程)流程:

  1. 浏览MQ队列(带锁定)并获取下一个可用消息
  2. 做一些可能会或可能不会失败的事情
  3. 一个。如果成功,从队列中删除消息并重新开始或b。如果不成功,请在队列中留言
  4. 我的问题源于我的应用程序可能在第2步和第3步之间意外死亡,然后应用程序在重新启动时会产生重复的消息。

    有没有办法将邮件标记为“脏”'或者'处理'在队列中(在阅读它的同时或之后),即使应用程序重新启动,标记仍然存在?

    我曾尝试使用MQ提供的标记,但它们无法在重新启动后继续存在。另一种可能性是将消息移至“处理”状态。队列,成功时将其删除或在失败时将其移回源队列,但这需要第二个队列,而不再是简单的代码。

    粗略代码示例:

    MQGetMessageOptions gmo = new MQGetMessageOptions(); 
    gmo.options = MQConstants.MQGMO_BROWSE_FIRST | MQConstants.MQGMO_LOCK;
    MQMessage message = new MQMessage();
    message.correlationId = MQC.MQCI_NONE;
    message.messageId     = MQC.MQMI_NONE;
    queue.get(message, gmo);
    
    boolean success = processMessage(message);
    
    // Application gets killed here after successful message processing.
    // Produces duplicate after restart.
    
    if (success) {
       MQGetMessageOptions gmo2 = new MQGetMessageOptions(); 
       gmo2.options = MQConstants.MQGMO_MSG_UNDER_CURSOR;
       queue.get(new MQMessage(), gmo2);
    }
    

    基本上,我想实现这个目标:

    • 从队列中非破坏性地获取消息(仅当未标记为"处理")
    • 将消息标记为"处理"在队列
    • 处理消息(包括发送到某个目的地)
    • 如果成功从队列中删除,或删除"处理"否则列在队列上

    如果应用程序在成功完成第三步'处理消息后立即死亡,则该消息将被标记为"处理"并且不会再次处理(因为它可能已经存在)。

    注意:我不希望此过程对消息处理有任何了解(除了成功之外)。

2 个答案:

答案 0 :(得分:0)

您是否尝试过SYNCPOINT?在这种情况下,提交或回退类型的操作可能有所帮助。

答案 1 :(得分:0)

你的解决方案是一个可怕的设计。如果要更新数据库,那么为什么不使用2阶段提交(即XA事务)?

让MQAdmin设置队列管理器以使用您正在使用的特定数据库的资源管理器,然后就像这样简单:

  • 启动交易(2阶段提交)
  • 从队列中获取消息(破坏性获取不浏览)
  • 更新数据库
  • 提交交易

因此,事务,MQGET和数据库更新中的所有内容将一起提交或一起退出。

如果您的应用程序崩溃,那么资源管理器将自动退出事务中的所有内容。

假设您不想使用2阶段提交,或者您没有更新数据库(更新文件),那么您可以使用单阶段UOW(工作单元)。

  • 使用MQGMO_SYNCPOINT的MQGMO选项
  • 从队列中获取消息(破坏性获取不浏览)
  • 更新您要更新的内容
  • 问题MQCMIT

关于MQ的事情:

  • 如果应用程序发出 MQDISC或正常结束 ,使用当前未提交的操作,则会执行 隐含的MQCMIT :IBM MQ,即在SYNCPOINT下完成的所有操作都已提交。

  • 如果应用程序 异常结束 ,使用当前未提交的操作,则会执行 隐含的MQBACK 通过IBM MQ,即回滚在SYNCPOINT下完成的所有操作。