我正在编写一个 .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 工作方式的理解,而且这似乎就是正在发生的事情。如果这不是默认行为,请纠正我。

有帮助吗?

解决方案

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

注意:MQOO是MQ打开选项和MQGMO是MQ获取消息选项

其他提示

您真的应该有独立的队列中这样做。日处理结束应该有自己的队列。当你处理你的消息的一部分,你送它到EOD队列。

随着你将不得不跟踪什么消息你已经某处处理浏览选项。

另外,还可以设置在拿到等待超时。所以,你不必“检查队列之前等待1秒”。由于现在写你不能打无味精可用的条件,因为你没有在获取消息选项设置NOWAIT。

有关子孙后代的缘故,这里的(我认为)的方法,大大改善版本的基础上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

我意识到我来讨论这个问题有点晚了,您可能已经编写了这个应用程序的代码。如果您需要修改它或其他任何可能需要做类似事情的人,我有一些观察结果。

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

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

这里的优点有几个:

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

这里还有几个完全不同的问题。其中之一是使用“如果停顿则失败”选项。这样做的目的是,当 QMgr 完全关闭时,此选项会导致您的 API 调用以指示 QMgr 正在关闭的返回代码结束。如果您不包含此选项,则 QMgr 可能会使用两个或多个连接的应用程序 绝不 干净地关闭,需要强制关闭或用暴力杀死其进程。通常,在所有支持它的 API 调用上始终使用 Fail if Quiescing。它存在的原因是为了那些需要 XA 事务性但由于某种原因无法使用它的人。在此场景中,如果静止设置且后续 GET 或 PUT 操作未设置,则 CONNECT 和第一个 GET 或 PUT 调用将使用“失败”。这会导致 QMgr 等待整组 GET/PUT 调用完成,但随后下一个 CONNECT 或 GET/PUT 使用 Fail if Quiescing,以便 QMgr 有机会在必要时关闭。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top