Как просмотреть сообщение Websphere MQ, не удаляя его? - PullRequest
7 голосов
/ 24 июня 2009

Я пишу приложение .NET Windows Forms, которое отправит сообщение в очередь 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 работает, и похоже, именно это и происходит. Пожалуйста, исправьте меня, если это не стандартное поведение.

Ответы [ 4 ]

11 голосов
/ 24 июня 2009

Вам нужно открыть очередь с опцией MQOO_BROWSE. Затем при первом чтении вы делаете GET, используя опцию MQGMO_BROWSE_FIRST. Наконец, ваши последующие GET должны использовать опцию MQGMO_BROWSE_NEXT.

Примечание. MQOO - это параметры открытия MQ, а MQGMO - параметры сообщения MQ.

1 голос
/ 07 мая 2010

Я понимаю, что приду к этой дискуссии немного поздно, и вы, вероятно, уже написали это приложение. Если вам когда-нибудь понадобится изменить его или кому-либо еще, кому может понадобиться сделать что-то подобное, у меня есть пара замечаний.

Во-первых, если вы можете сделать это с клиентом v7 QMgr и v7 WMQ, это будет предпочтительным решением. В версии 7 поддержка .Net была перемещена из SupportPac в часть базового продукта. Появилась новая функциональность, исправлены некоторые ошибки и улучшена производительность. Кроме того, на v7 вы можете использовать pub-sub ... что подводит меня ко второму наблюдению.

Исходя из описания в исходном посте, я бы сделал это в Pub-Sub. Приложение, которое помещает сообщение, должно поместить только одно, и ему даже не нужно знать, что оно помещает в тему. Вы можете создать псевдоним для темы, которая будет выглядеть как очередь для производителя сообщений. Приложения-потребители могут либо подписаться, либо вы можете создать две административные подписки, чтобы опубликованные сообщения попадали в две назначенные вами очереди. Каждое из ваших приложений имеет выделенную очередь, и для производителя и пакетного приложения не требуется никаких изменений в кодировании, это просто конфигурация. Конечно, приложение, управляющее транзакциями, должно будет на самом деле потреблять сообщения, а не просматривать их.

Преимуществ здесь несколько:

  • Когда очередь заполняется сообщениями, индексирование сбрасывается на диск, и выше порогового значения вы увидите снижение производительности, которое может быть значительным. Поэтому текущий метод не так хорошо масштабируется.
  • С помощью метода pub-sub вы можете иметь несколько экземпляров приложений реального времени, пакетных приложений или обоих, и они могут быть в одном или другом QMgr. Масштабировать легко.
  • Вы устраняете зависимость между приложениями реального времени и пакетными приложениями, которые должны быть в одном QMgr.
  • Более прозрачное управление. Если вы видите сообщения, накапливающиеся в очереди в реальном времени, вы знаете, что у вас есть проблема.

Пара совершенно разных вопросов. Одним из них является использование опции Fail if Quiescing. Цель этого состоит в том, что, когда QMgr выключается полностью, эта опция заставляет ваш вызов API завершаться с кодом возврата, указывающим, что QMgr закрывается. Если вы не включите эту опцию, то с двумя или более подключенными приложениями возможно, что QMgr будет никогда не выключаться чисто, и его нужно будет принудительно выключить или убить его процессы с помощью грубой силы. Как правило, всегда используйте Fail, если Quiescing на всех вызовах API, которые его поддерживают. Причина, по которой он вообще существует, для людей, которым нужна транзакционность XA, но по какой-то причине они не могут ее использовать. В этом сценарии CONNECT и первый вызов GET или PUT используют Fail, если нет установленного Quiescing, а последующие операции GET или PUT - нет. Это заставляет QMgr ожидать завершения всего набора вызовов GET / PUT, но затем следующий CONNECT или GET / PUT использует Fail, если Quiescing, так что QMgr имеет возможность завершить работу при необходимости.

Другое замечание здесь заключается в том, что здесь нет кода Catch. Я предполагаю, что есть еще одна область действия вверх по стеку вызовов? Всегда желательно напечатать код возврата WMQ из исключения, чтобы вы могли найти основную причину. В консультациях я всегда советую клиентам, что невозможность напечатать код возврата (или связанное исключение для кода JMS / XMS) является демонстрацией, которая должна препятствовать продвижению приложения в Production. Это действительно так важно. Даже если у вас есть перехват в коде, который вызывает getMessage (), кто-то, повторно использующий здесь фрагмент кода примера, может не осознавать, что этот важный фрагмент отсутствует.

1 голос
/ 25 июня 2009

Ради потомков, вот (я думаю) намного улучшенная версия метода, основанная на ответах мамбокинга и Джумучелло.

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
1 голос
/ 24 июня 2009

Вы действительно должны делать это с отдельными очередями. Обработка на конец дня должна иметь свою очередь. После обработки вашей части сообщения вы отправляете ее в очередь EOD.

С помощью функции просмотра вам придется отслеживать, какие сообщения вы уже где-то обработали.

Кроме того, вы можете установить время ожидания на GET. Поэтому вам не нужно «ждать 1 секунду, прежде чем проверять очередь». Как написано прямо сейчас, вы не можете выполнить условие «Нет доступных сообщений», потому что вы не установили NOWAIT в опциях получения сообщений.

...