如何浏览 Websphere MQ 消息而不删除它?

Posted

技术标签:

【中文标题】如何浏览 Websphere MQ 消息而不删除它?【英文标题】:How do I browse a Websphere MQ message without removing it? 【发布时间】:2010-11-05 13:42:12 【问题描述】:

我正在编写一个 .NET Windows 窗体应用程序,它将向 Websphere MQ 队列发布消息,然后轮询另一个队列以获取响应。如果返回响应,应用程序将实时处理部分响应。但是响应需要保留在队列中,以便每日批处理作业(也从响应队列中读取)可以完成其余的处理。

我已经阅读了该消息。我一直想不通的是如何在不删除它的情况下阅读它。

这是我到目前为止所得到的。我是 MQ 新手,所以任何建议都将不胜感激。并随时使用 C# 进行响应。

Public Function GetMessage(ByVal msgID As String) As MQMessage
    Dim q = ConnectToResponseQueue()
    Dim msg As New MQMessage()
    Dim getOpts As New MQGetMessageOptions()
    Dim runThru = Now.AddMilliseconds(CInt(ConfigurationManager.AppSettings("responseTimeoutMS")))
    System.Threading.Thread.Sleep(1000) 'Wait for one second before checking for the first response'
    While True
        Try
            q.Get(msg, getOpts)
            Return msg
        Catch ex As MQException When ex.Reason = MQC.MQRC_NO_MSG_AVAILABLE
            If Now > runThru Then Throw ex
            System.Threading.Thread.Sleep(3000)
        Finally
            q.Close()
        End Try
    End While
    Return Nothing 'Should never reach here'
End Function

注意:我尚未验证我的代码是否确实删除了该消息。但这就是我理解 MQ 工作的方式,这似乎就是正在发生的事情。如果这不是默认行为,请纠正我。

【问题讨论】:

+1 - 我希望在自己弄清楚之前发现这个问题。 【参考方案1】:

您需要使用 MQOO_BROWSE 选项打开队列。然后在您第一次阅读时,您使用 MQGMO_BROWSE_FIRST 选项执行 GET。最后,您后续的 GET 应该使用 MQGMO_BROWSE_NEXT 选项。

注意:MQOO 是 MQ 开放选项,MQGMO 是 MQ 获取消息选项。

【讨论】:

出色的答案。这救了我今天的培根。谢谢。【参考方案2】:

您确实应该使用单独的队列来执行此操作。日终处理应该有自己的队列。处理完您的部分消息后,将其发送到 EOD 队列。

使用“浏览”选项,您将不得不跟踪您已经在某处处理过哪些消息。

此外,您可以在 GET 上设置等待超时。所以你不需要“在检查队列之前等待 1 秒”。正如现在所写的那样,您无法达到 no msg available 条件,因为您没有在获取消息选项中设置 NOWAIT。

【讨论】:

+1 好点。我没有在我的帖子中提到我一次只做一个请求和响应。响应的相关 ID 将与请求的消息 ID 匹配,因此跟踪我已经处理的消息应该不是问题。至于等待超时,我已经看到了,但还没有弄清楚如何处理它。我根据您的建议进行了更多研究,并使用该方法大幅清理了该方法。非常感谢!【参考方案3】:

为了后代,这里是(我认为)基于 mamboking 和 jmucchiello 答案的方法的改进版本。

Public Function GetMessage(ByVal correlID As Byte()) As MQMessage
    Dim waitInterval = CInt(ConfigurationManager.AppSettings("responseTimeoutMS"))
    Dim q As MQQueue = Nothing
    Try
        Dim msg As New MQMessage()
        Dim getOpts As New MQGetMessageOptions()
        q = ConnectToResponseQueue()
        msg.MessageId = MQC.MQMI_NONE
        msg.CorrelationId = correlID
        getOpts.MatchOptions = MQC.MQMO_MATCH_CORREL_ID
        getOpts.WaitInterval = waitInterval
        getOpts.Options = MQC.MQGMO_BROWSE_FIRST Or MQC.MQGMO_WAIT
        q.Get(msg, getOpts)
        Return msg
    Finally
        If q IsNot Nothing AndAlso q.IsOpen() Then q.Close()
    End Try
End Function

【讨论】:

【参考方案4】:

我意识到我来这个讨论有点晚了,你可能已经编写了这个应用程序。如果您需要修改它或其他任何可能需要做类似事情的人,我有几点意见。

首先,如果您可以使用 v7 QMgr 和 v7 WMQ 客户端执行此操作,这将是首选解决方案。在 v7 中,.Net 支持已从 SupportPac 移至基础产品的一部分。有相当多的新功能,一些错误修复和更好的性能。此外,在 v7 上,您可以使用 pub-sub...这让我想到了第二个观察结果。

根据原始帖子中的描述,我会在 Pub-Sub 中完成此操作。放置消息的应用程序只需要放置一个,它甚至不需要知道它正在放置一个主题。实际上,您可以为主题设置别名,使其看起来像消息生产者的队列。然后,您的消费应用程序可以订阅,或者您可以进行两个管理订阅,以便发布的消息进入您指定的两个队列。然后,您的应用程序每个都有一个专用队列,并且生产者和批处理应用程序不涉及任何编码更改,这只是配置。当然,驱动事务的应用程序需要实际使用消息而不是浏览它们。

这里有几个优点:

当队列填满消息时,索引会被刷新到磁盘并且超过阈值时,您会看到性能下降,这可能很严重。因此,当前的方法并不能很好地扩展。 使用 pub-sub 方法,您可以拥有实时或批处理应用程序或两者的多个实例,这些实例可以位于相同或不同的 QMgr 上。扩大规模很容易。 您消除了需要在同一个 QMgr 上的实时应用和批处理应用之间的依赖关系。 更透明的管理。如果您看到消息在实时队列中堆积,您就知道您遇到了问题。

这里还有几个完全不同的问题。其中之一是使用 Fail if Quiescing 选项。这样做的目的是,当 QMgr 完全关闭时,此选项会导致您的 API 调用以指示 QMgr 正在关闭的返回码结束。如果您不包含此选项,则可能有两个或多个连接的应用程序,QMgr永远完全关闭,需要强制关闭或用蛮力杀死其进程。作为一项规则,始终在所有支持它的 API 调用上使用 Fail if Quiescing。它存在的原因是那些需要 XA 事务性但由于某种原因不能使用它的人。在这种情况下,CONNECT 和第一个 GET 或 PUT 调用使用 Fail if Quiescing set 和后续 GET 或 PUT 操作没有。这会导致 QMgr 等待整个 GET/PUT 调用集完成,然后下一个 CONNECT 或 GET/PUT 使用 Fail if Quiescing,因此 QMgr 有机会在必要时关闭。

这里的另一个观察是这里的代码中没有 Catch。我猜在调用堆栈的范围内还有一个?始终建议从异常中打印 WMQ 返回代码,以便您可以追踪根本原因。在咨询业务中,我总是建议客户未能打印返回代码(或 JMS/XMS 代码的链接异常)是一个阻碍将应用程序推广到生产环境的障碍。这真的很重要。即使您在调用 getMessage() 的代码中遇到了问题,但在此处重用示例代码 sn-p 的人可能不会意识到缺少这一重要部分。

【讨论】:

【参考方案5】:

供阅读:

AccessQueue 选项:MQOO_BROWSE 和 MQGetMessageOptions:MQGMO_BROWSE_NEXT

【讨论】:

最高投票和接受的答案已经说明了您所说的并提供了更多详细信息,为什么要发布部分答案作为您自己的答案?

以上是关于如何浏览 Websphere MQ 消息而不删除它?的主要内容,如果未能解决你的问题,请参考以下文章

结合使用WebSphere MQ和Twisted

如何正确设置IBM WebSphere MQ 实现群发消息

在 WebSphere MQ 中配置死信队列

WebSphere MQ消息通道管理总结

使用 ASCII 编码通过 WebSphere MQ 向 SWIFT 发送消息

Websphere MQ C++ 多线程