Интеграция приложений на основе WebSphere MQ

Работа с MsgId и CorrelId


Теперь полезно изучить способы контроля доставки сообщений, тем более что для этого существуют специальные поля в дескрипторе сообщений: MsgId и CorrelId. Например, некоторое приложение отправляет запросы на обработку в очередь Queue1 и ожидает уведомления о доставке в очереди ReplyToQ = Queue2. Совершенно очевидно, что уведомления о доставке не обязаны появиться в очереди Queue2 в той же последовательности, в какой отправлялись запросы в очередь Queue1. Как же в таком случае отслеживать доставку сообщений?

Другой пример, приложение отправляет запросы в разные системы, в частности, по банковским счетам клиента и по проверке его кредитной истории и ожидает получить ответ от запрашиваемых систем в одну и ту же очередь для всех клиентов. Как же идентифицировать поступающие ответы? Самое простое - использовать идентификаторы MsgId и CorrelId, которые являются уникальными для каждого сообщения и создаются на основе времени выполнения команды MQPUT. Идентификаторы MsgId и CorrelId создаются менеджером, если они установлены в NULL, либо заданы опции MQPMO_NEW_MSG_ID и/или MQPMO_NEW_CORREL_ID; в противном случае, MsgId и CorrelId создаются приложением.

Таким образом, задавая значения MsgId и CorrelId при выполнении MQPUT, появляется возможность автоматически получать значения MsgId и CorrelId при чтении командой MQGET. При этом не надо забывать, что в цикле считывания перед командой MQGET следует ставить обнуление этих переменных (MsgId=MQMI_NONE и CorrelId=MQCI_NONE), иначе можно получить ошибку считывания сообщений из очереди MQRC_NO_MSG_AVAILABLE, несмотря на то, что сообщения в очереди имеются.

Рассмотрим на примере, как работает MQGET с MsgId и CorrelId на практике. Пусть в некоторую очередь поступили сообщения в определенном порядке, как указано в таблице ниже.

Номер сообщенияMSGIDCORRELID
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 3 1

Теперь варьируя MsgId и CorrelId, можно читать самые разные сообщения.

MQGET (MSGID= MQMI_NONE, CORRELID= MQCI_NONE) читает первое доступное сообщение независимо от MsgId и CorrelId, то есть сообщение 1.


MQGET (MSGID= MQMI_NONE, CORRELID= 3) может прочитать только одно сообщение, имеющее значение CorrelId = 3, это сообщение 3.

MQGET (MSGID= 2, CORRELID= MQCI_NONE) читает первое сообщение со значением MsgId = 2, это сообщение 4.

MQGET (MSGID= 2, CORRELID= 2) может прочитать только одно сообщение, имеющее уникальное сочетание MsgId = 4 и CorrelId = 2, это сообщение 5.

Таким образом, если никакие другие сообщения не поступят в очередь, то в очереди после четырех MQGET останутся 2 сообщения. Здесь уместен вопрос о производительности работы менеджера очередей при таком поиске сообщений. Если число сообщений в очереди не превышает 100, то время поиска будет незначительным, оно практически не зависит от числа сообщений. Но если число сообщений в очереди превысит 1000, то менеджер будет сканировать очередь и время поиска будет заметным. На OS/390 MQSeries администратор может определить MsgId или CorrelId (но не одновременно) как индекс и это существенно ускорит поиск нужного сообщения в очереди. Следует также отметить, что на других платформах (AS/400, HP_UX, AIX, Sun Solaris, Windows) в версии 5.3 WebSphere MQ можно использовать опции соответствия MatchOption: MQMO_MATCH_MSG_ID и MQMO_MATCH_CORREL_ID. Если эти опции соответствия не будут определены, то MsgId и CorrelId будут игнорироваться, как если бы использовались опции MQMI_NONE и MQCI_NONE и будет извлекаться очередное сообщение.

Сформулируем одно общее правило при разработке программ с контролем доставки сообщений с помощью MsgId и CorrelId: если приложение перемещает сообщение из входной очереди в выходную, то MsgId входного сообщения перемещается в CorrelId выходного сообщения и создается новый уникальный идентификатор MsgId выходного сообщения. На уровне псевдокода это правило можно записать следующим образом:

INPUT_MSG_DESC.MsgId = MQMI_NONE; INPUT_MSG_DESC.CorrelId = MQCI_NONE; MQGET (..........); /* Обработка входного сообщения */ OUT_MSG_DESC.MsgId = MQMI_NONE; OUT_MSG_DESC.CorrelId = INPUT_MSG_DESC.MsgId; MQPUT (..........);



Разрабатывая логику в цепи программ- обработчиков сообщений на разных платформах следует стремиться к тому, чтобы CorrelId содержал MsgId исходного запроса, а MsgId выходного сообщения содержал уникальный идентификатор, полученный наиболее важной в функциональном смысле выходной программой. На основе такой логики легко получить подтверждение на выходе, что исходный запрос был отработан, и промежуточные программы проставили свой MsgId в выходном сообщении. Это позволяет осуществить контроль времени прохождения запроса и получения сообщения-отчета.

В завершение раздела, уж если речь пошла о контроле доставки сообщений, необходимо отметить возможность использования полей context (контекст) в дескрипторе сообщения для контроля авторизации пользователя и обеспечения безопасности. Группа полей context состоит из 8 полей, их значения по умолчанию приводятся в таблице ниже.

ПолеРазмерЗначениеПолеРазмерЗначение
UserIdentifier CHAR12 Имя пользователя PutAppName CHAR28 Имя приложения
AccountingToken BYTE32 Учетный номер приложения-отправителя PutDate CHAR8 YYYYMMDD
AppIdentityData CHAR32 Пробелы PutTime CHAR8 HHMMSSTH
PutApplType LONG UNIX и т.п. AppOriginData CHAR4 пробелы
Используя UserIdentifier и AccountingToken, а также опции для работы с полями context такими как MQPMO_DEFAULT_CONTEXT, MQPMO_PASS_IDENTITY_CONTEXT, MQPMO_PASS_ALL_CONTEXT, MQPMO_SET_IDENTITY_CONTEXT, MQPMO_SET_ALL_CONTEXT, а также MQOO_ALTERNATE_USER_AUTHORITY [14] для альтернативной авторизации, позволяющей одному пользователю посылать сообщения от имени другого, можно контролировать авторизацию пользователей, запускающих задачи. Эти права устанавливает MQSeries - администратор с помощью команды setmqaut. Об этом не следует забывать при разработке приложений.


Содержание раздела