Как просмотреть сообщение Websphere MQ, не удаляя его?

StackOverflow https://stackoverflow.com/questions/1039240

  •  22-07-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

Ради потомков, вот (я думаю) намного улучшенная версия метода, основанная на ответах мамбокинга и 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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top