Наводим мосты – 2: Синхронно – Асинхронный вариант

nbridge2
Продолжаем разбирать решения задачи об интеграции разнородных интерфейсов при помощи мостов.
Продолжение, начало здесь:
SAP PI Async-Sync Bridge. Наводим мосты или как связать между собой асинхронный и синхронный интерфейсы без помощи ccBPM.

Содержание:
3. Sync-Async Bridge и его модули – RequestOnewayBean, WaitResponseBean и NotifyResponseBean
     3.1 Синхронно-асинхронный мост с модулями в Sender Communication Channel
     3.2 Пример синхронно-асинхронного моста с модулями в Sender Communication Channel
     3.3 Синхронно-асинхронный мост с модулями в Receiver Communication Channel
     3.4 Пример синхронно-асинхронного моста с модулями в Receiver Communication Channel
 

3. Sync-Async Bridge и его модули – RequestOnewayBean, WaitResponseBean и NotifyResponseBean


Давайте представим себе другую задачу: в процессе работы исходной системе требуется передать некоторую информацию внешней системе и тут же получить подтверждение об успешном приеме, либо ошибке.
Внешняя система работает только асинхронно, то есть информацию для сохранения система принимает на один сервис (это может быть файл, асинхронный SOAP, SQL, HTTP и др.), а подтверждение приема выдается через некоторое время с другого сервиса.
Напомню схему такого рода интерфейсов:
Синхронно - Асинхронный мост

Рис.1: Синхронно – Асинхронный мост

За работу синхронно-асинхронного моста отвечают следующие модули:

  • RequestOnewayBean отвечает за преобразование синхронного сообщения в асинхронное.
  • WaitResponseBean – оставляет канал связи с исходной системой открытым и ждет возврата ответа. При получении асинхронного ответа – переводит его в синхронное сообщение и отправляет исходной системе. Если ответ не приходит за заданное время – отправляет исходной системе сообщение об ошибке.
  • NotifyResponseBean – модуль, который используется вместо стандартного модуля адаптера в канале-отправителе ответа для прямой передачи сообщения в WaitResponseBean (минуя подсистему обработки сообщений PI).

Модули RequestOnewayBean и WaitResponseBean могут быть использованы как в канале-отправителе (sender communication channel), так и в канале-получателе (receiver communication channel). RequestOnewayBean вставляется до стандартного модуля адаптера (обычно CallSAPAdapter); WaitResponseBean – после.

Для включения модулей в канал связи нужно перейти на вкладку “Module” канала связи и внести следующие значения:

Module Name Type Module Key
AF_Modules/RequestOnewayBean Local Enterprise Bean RqOneWay
AF_Modules/WaitResponseBean Local Enterprise Bean WResp
AF_Modules/NotifyResponseBean Local Enterprise Bean WResp

“Module Key” может быть любым – главное, чтобы он был уникальным и ключи было бы сложно перепутать – это поможет нам впоследствии при определении параметров модулей.

Дальнейшие настройки зависят от размещения модулей — в канале-отправителе (sender communication channel) или канале-получателе (receiver communication channel).

Надо сказать об одной из проблем синхронно-асинхронного моста. Представим себе, что через мост одновременно проходят несколько сообщений. Значит, в какой-то момент несколько отправленных запросов ожидают ответа. После обработки запроса из целевой системы начинают поступать сообщения – как узнать, кому из ожидающих каналов нужно отправить конкретный ответ?

Рис.2: задача определения получателя асинхронного ответа

Рис.2: задача определения получателя асинхронного ответа


Здесь на помощь приходит такая сущность как корреляция(correlation). Корреляция – это некий идентификатор, “ключ”, по которому проводится соответствие между ответом и ожидающим его приемником.

Термин “корреляция” также можно встретить в Sync-Async Bridge в BPM – там корреляцией может выступать целый набор идентификаторов.

То есть задача состоит в том, чтобы на этапе отправки асинхронного сообщения “запомнить” некоторый идентификатор, а на этапе приема ответа проверить возвращаемое значение ключа.

Рис.3:  определение получателя асинхронного ответа при помощи корреляции

Рис.3: определение получателя асинхронного ответа при помощи корреляции

В нашем случае для корреляции используется параметр в заголовке сообщения-ответа от асинхронной системы – correlationID, который должен быть равен идентификатору сообщения PI (Message GUID) исходного синхронного сообщения-запроса. Этот параметр принадлежит к группе Adapter-Specific Message Attributes и может быть изменен при помощи стандартного модуля DynamicConfigurationBean.

В примере из документации SAP (“Configuring the Async/Sync Bridge Using the JMS Adapter” для задания корреляции используются стандартные параметры настройки каналов связи JMS (параметр “Set PI Conversation ID”).

В других видах адаптеров подобный стандартный параметр отсутствует и приходится идти на некоторые хитрости – в частности, сохранять Message GUID и заполнять correlationID в ответе самостоятельно или с помощью целевой системы. В примере ниже (3.2) вы можете найти один из способов работы с файловым адаптером.

3.1 Синхронно-асинхронный мост с модулями в Sender Communication Channel

Логика работы модулей в Sender Channel следующая:

Рис.2: Логика работы синхронно-асинхронного моста при размещении модулей в канале связи отправителя.

Рис.4: Логика работы синхронно-асинхронного моста при размещении модулей в канале связи отправителя.

  1. Прием синхронного запроса по каналу связи с внешней системой, передача его модулю RequestOnewayBean. Модуль меняет тип сообщения с синхронного на асинхронный.
  2. В зависимости от параметра passThrough сообщение либо передается дальше по цепочке модулей, либо напрямую в подсистему обработки PI (пропуская п.3).
  3. Обработка сообщения стандартным модулем адаптера, передача его в подсистему обработки сообщений PI.
  4. Передача запроса на асинхронный канал связи.
  5. Асинхронный вызов внешней системы.
  6. Прием ответа из асинхронного канала связи.
  7. Возврат ответа в модуль NotifyResponseBean, который передает ответ напрямую в модуль WaitResponseBean, минуя подсистему обработки сообщений PI.
  8. WaitResponseBean меняет тип сообщения с асинхронного на синхронный и возвращает его в исходную систему.

Параметры модуля RequestOnewayBean при размещении его в Sender Communication Channel:

Параметр Назначение Возможные
значения
Значения
по умолчанию
passThrough Определяет, куда модуль должен передать обработанное сообщение:
– подсистеме обработки сообщений PI – false;
– следующему модулю в цепочке – true
true/false false

Параметры модуля WaitResponseBean при размещении его в Sender Communication Channel:

Параметр Назначение Возможные
значения
Значения
по умолчанию
timeout Определяет время ожидания ответа модулем Время в миллисекундах 300000

Модуль NotifyResponseBean в этой конфигурации размещается в канале, принимающем ответ от асинхронной системы, причем модуль ставится вместо стандартного модуля адаптера.

Параметры модуля NotifyResponseBean следующие:

Параметр Назначение Возможные значения Значения по умолчанию
timeout Определяет время ожидания модуля Время в миллисекундах 300000
fault Наименование сообщения об ошибке Например, SA_BRIDGE_ERROR
faultNamespace Пространство имен сообщения об ошибке:
http://sap.com/xi/XI/System – ошибка будет считаться системной (system error);
любое другое пространство имен – ошибка будет считаться ошибкой приложения (application error).
После того, как мы настроили все необходимые модули, нам необходимо настроить корреляцию запроса и ответа.

Для этого нужно каким-то образом сохранить GUID сообщения и передать его целевой системе. Та, в свою очередь, должна вернуть ответ с упоминанием этого GUID и, при получении ответа, нужно заполнить параметр заголовка сообщения в разделе Dynamic Configuration, отвечающий за корреляцию ответа с запросом – correlationId сохраненным значением.
Для каждого из типов адаптеров может быть свое решение, ниже, в примере, мы рассмотрим вариант для файлового адаптера.

После настройки корреляции остается только создать правила маршрутизации, связывающие исходный интерфейс в синхронной системе с целевым интерфейсом – запросом к асинхронной системе.
Для маршрутизации ответа достаточно создать лишь Sender Agreement – все остальное сделает модуль NotifyResponseBean.

3.2 Пример синхронно-асинхронный моста с модулями в Sender Communication Channel


Давайте рассмотрим все на конкретном примере. Бизнес-легенда будет такой: у нас есть внешний клиент, который с помощью синхронного web-сервиса передает нам информацию о поступивших на склад книгах. PI, в свою очередь, должен получить эту информацию и передать ее в асинхронную базу данных. Интерфейс с базой данных основан на файловом обмене, статус операции в базе также возвращается в виде файла. PI, получив статус, должен вернуть его клиенту.
Рис.5: Схема примера

Рис.5: Схема примера

Для реализации этого интерфейса нам понадобятся следующие объекты разработки:

Рис.6: Объекты разработки в Integration Repository

Рис.6: Объекты разработки в Integration Repository

Обратите внимание на мэппинг операций интерфейсов – он хоть и синхронный, но “однобокий” – работает только в одну сторону. Для его создания понадобиться прием с временной подменой типа интерфейса, подобный мэппингу из предыдущей статьи о асинхронно-синхронных мостах.

Затем в Integration Builder создаем все необходимые объекты маршрутизации:

Рис.:7: Объекты настройки

Рис.:7: Объекты настройки

Может возникнуть вопрос – как маршрутизация ответа может быть проведена одним Sender Agreement?
Можно настроить и полную маршрутизацию или сделать возврат ответа через Integrated Configuration. Но в данном случае это не имеет смысла – ответ все равно будет передан модулем NotifyResponseBean напрямую ожидающему модулю WaitResponseBean, минуя подсистему обработки сообщений PI.

Теперь расставим модули по местам.
Синхронный канал связи SOAP:

Рис.:8: Синхронный канал связи SOAP Sender

Рис.:8: Синхронный канал связи SOAP Sender

Не забудьте указать Quality Of Service = Best Effort, то есть обозначить канал, как синхронный.

Затем добавляем модули RequestOnewayBean и WaitResponseBean:

Рис.:9: Модули синхронного канала связи SOAP Sender

Рис.:9: Модули синхронного канала связи SOAP Sender

Затем настраиваем файловый канал связи для отправки запроса к базе данных:

Рис.:10: асинхронный файловый канал связи для отправки запроса.

Рис.:10: асинхронный файловый канал связи для отправки запроса.

Обратите внимание на настройку имени файла. Имя файла формируется переменной, в которую в момент выполнения записывается значение Message ID.
То есть имя файла – это GUID сообщения, без каких-либо расширений.

Зачем это нужно? Таким образом в нашем примере мы сохраняем GUID сообщения-запроса. В реальности можно сделать также, можно передавать GUID в теле сообщения. Главное – чтобы целевая система его получила, сохранила и вернула в доступном для PI виде вместе с ответом.

Настраиваем файловый канал связи для возврата ответа:

Рис.:11: Настройки асинхронного файлового канала связи для ответа от целевой системы

Рис.:11: Настройки асинхронного файлового канала связи для ответа от целевой системы

Будем считать, что система выдает ответ в другую директорию в виде XML-файла. Имя этого файла – все тот же GUID исходного запроса.

Настраиваем модули:

Рис.:12: Модули асинхронного файлового канала связи для ответа от целевой системы

Рис.:12: Модули асинхронного файлового канала связи для ответа от целевой системы

Используя стандартный модуль DynamicConfigurationBean мы записываем имя файла в заголовок PI сообщения, в параметр correlationId – то есть заполняем корреляцию для дальнейшей обработки ответа.
Модуль NotifyResponseBean замещает стандартный модуль адаптера CallSAPAdapter и пересылает ответ напрямую ожидающему модулю моста. Если к этому моменту ответа с таким значением корреляции уже никто не ждет – то возникнет ошибка корреляции, что отобразится в логах.

Ну вот все настройки выполнены, время проверять наш мост.
Формируем WSDL web-сервиса (контекстное меню на Integrated Configuration -> Display WSDL). Затем, используя любой инструмент отправки SOAP-запроса (я использовал freeware инструмент SOAPUI) и сохраненный WSDL, формируем запрос к PI.

Рис.:13: Отправка синхронного запроса от SOAPUI

Рис.:13: Отправка синхронного запроса от SOAPUI

После отправки в директории появляется файл с именем-идентификатором сообщения и запросом внутри.

Рис.:14: Файл-запрос получен целевой системой

Рис.:14: Файл-запрос получен целевой системой

Дальше имитируем работу системы-получателя.
Меняем содержимое файла на ответ:

Рис.:15: Файл-ответ со статусом операции

Рис.:15: Файл-ответ со статусом операции

И перемещаем его в директорию books/status. Если мы были достаточно быстры, то файл будет обработан PI и итог в SOAPUI будет выглядеть так:

Рис.:16: Ответ успешно получен SOAP-клиентом

Рис.:16: Ответ успешно получен SOAP-клиентом

Синхронно-асинхронный мост успешно заработал. На этом можно было бы закончить, но..
Представьте себе – пришел наш заказчик и попросил добавить к ответу еще одно поле – метку времени.
Обратного мэппинга у нас нет, целевая система тоже “не умеет” отвечать нужным образом.
Что делать?

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

Создадим в репозитарии новый асинхронный входящий интерфейс на базе формата ответа, требуемого внешним клиентом.

Рис.16: Дополнительные объекты разработки в Integration Repository

Рис.16: Дополнительные объекты разработки в Integration Repository

Определим также мэппинг, который будет преобразовывать ответ от системы BS_ExtDB в формат ответа для BS_WebClient.

Рис.17: Преобразование ответа в нужный формат

Рис.17: Преобразование ответа в нужный формат

Теперь настроим маршрутизацию в Integration Directory:

  • создадим новый псевдо-файловый канал связи CC_Dummy_file_receiver и перенесем туда модули моста DynamicConfigurationBean и NotifyResponseBean со всеми параметрами;
  • восстановим стандартный модуль CallSAPAdapter в канале СС_ExtDB_FileSender;
  • удалим Sender Agreement для СС_ExtDB_FileSender;
  • создадим и настроим Integrated Configuration для маршрутизации ответа от BS_ExtDB до BS_WebClient.
Рис.:18: Дополнительные объекты настройки

Рис.:18: Дополнительные объекты настройки

Проверяем наш мост тем же самым образом и получаем нужный ответ:

Рис.:19: Ответ со статусом операции и временной меткой

Рис.:19: Ответ со статусом операции и временной меткой

Вот теперь – все, заказчик удовлетворен, синхронно-асинхронный мост работает как часы.

3.3 Синхронно-асинхронный мост с модулями в Receiver Communication Channel

Особых отличий от предыдущего варианта почти нет – те же три модуля: два из них – в асинхронном Receiver Communication Channel, передающем запрос целевой системе; третий – в асинхронном Sender Communication Channel, принимающем ответ.

Рис. 20: Логика работы синхронно-асинхронного моста при размещении модулей в каналах связи получателя.

Рис. 20: Логика работы синхронно-асинхронного моста при размещении модулей в каналах связи получателя.

  1. Прием синхронного запроса от внешней системы.
  2. Передача сообщения-запроса подсистеме обработки сообщений PI.
  3. Передача сообщения-запроса в асинхронный канал связи модулю RequestOnewayBean. Модуль меняет тип сообщения с синхронного на асинхронный.
  4. Сообщение поступает на стандартный модуль адаптера.
  5. Асинхронный вызов внешней системы.
  6. Получение асинхронного ответа на вход модуля NotifyResponseBean, заменяющего собой стандартный модуль адаптера.
  7. Передача запроса на модуль WaitResponseBean с проверкой корреляции.
  8. Модуль меняет тип сообщения с асинхронного на синхронный, затем передает сообщение-ответ подсистеме обработки сообщений PI.
  9. Передача сообщения-ответа в синхронный канал связи
  10. Возврат ответа исходной системе

Параметры модулей синхронно-асинхронного моста от размещения не зависят.

Обратите внимание – в документации SAP есть другая информация, там даны дополнительные параметры при размещении в Receiver Channel. Разумного применения этим параметрам я так и не нашел.

Параметры модуля RequestOnewayBean:

Параметр Назначение Возможные
значения
Значения
по умолчанию
passThrough Определяет, куда модуль должен передать обработанное сообщение:
– напрямую получателю – false;
– следующему модулю в цепочке – true
true/false false

Параметры модуля WaitResponseBean:

Параметр Назначение Возможные
значения
Значения
по умолчанию
timeout Определяет время ожидания ответа модулем Время в миллисекундах 300000

Параметры модуля NotifyResponseBean:

Параметр Назначение Возможные значения Значения по умолчанию
timeout Определяет время ожидания модуля Время в миллисекундах 300000
fault Наименование сообщения об ошибке Например, SA_BRIDGE_ERROR
faultNamespace Пространство имен сообщения об ошибке:
http://sap.com/xi/XI/System – ошибка будет считаться системной (system error);
любое другое пространство имен – ошибка будет считаться ошибкой приложения (application error).

Помимо настройки всех модулей нужно также позаботиться о заполнении корреляции.

3.4 Пример синхронно-асинхронного моста с модулями в Receiver Communication Channel


Давайте перестроим наш пример из пункта 3.2 на новый лад:
Рис.21: Объекты разработки в Integration Repository

Рис.21: Объекты разработки в Integration Repository

На этот раз нам нужны два синхронных интерфейса – SI_WebClient_SaveBook_sync и SI_ExtDB_SaveBook_sync, а также мэппинг между ними – OM_SaveBook_WebClient_to_ExtDB. Понадобиться также асинхронный интерфейс SI_ExtDB_Status (должен быть основан на том же message type, что и ответ в интерфейсе SI_ExtDB_SaveBook_sync) – через него мы будем возвращать ответ от асинхронной системы.

В Integration Directory настроим маршрутизацию следующим образом:

Рис.:22: Объекты настройки

Рис.:22: Объекты настройки

Уберем с SOAP-канала все модули и переставим их в файловые каналы:

Рис.:23: асинхронный файловый канал связи для отправки запроса.

Рис.:23: асинхронный файловый канал связи для отправки запроса.

Рис.:24: асинхронный файловый канал связи для получения ответа.

Рис.:24: асинхронный файловый канал связи для получения ответа.

Перенастроим Integrated Configuration – у нас новые каналы связи отправителя-получателя, интерфейс и мэппинг; из прежнего – только целевая система.
Для получения файла-ответа нам понадобится только Sender Agreement, настроенный на канал связи CC_ExtDB_File_Sender_WithModule и интерфейс SI_ExtDB_Status.

Используя SOAPUI, запускаем тестирование. В файловой системе должен появиться файл-запрос. Меняем его содержимое на ответ, перемещаем в ту папку, откуда PI забирает ответы, ждем обработки – и получаем следующую картинку:

Рис.:25: Запрос и результат работы моста в SOAPUI

Рис.:25: Запрос и результат работы моста в SOAPUI

Если у Вас картинка похожа на мою – поздравляю, Вы построили действующий синхронно-асинхронный мост!

——————————————————-
Продолжение: Наводим мосты – 3: экзотика и рекомендации.

8 thoughts on “Наводим мосты – 2: Синхронно – Асинхронный вариант

  1. Женя.

    Титанический труд. Мне б ваше трудоблюбие, я б уже наверное всю свою документацию дописал 🙂 Ну и бедный адаптер энжин. Думаю создатели таких паззлов не ожидали. Надо будет разобрать модель как нибудь, посмотреть как ожидание реализовано…

    Reply
    1. pitroff.ru Post author

      Спасибо, Женя!

      Я стандартную документацию тоже писать не люблю – там, как правило, “воды” много, ее сложно выдумывать. )

      А ожидание сделано через некий стандартный объект com.sap.aii.af.service.util.orch.Synchronizer, ему скармливается сообщение и таймаут. – глубже я не копал пока.

      Reply
    2. Евгений

      Я думаю, создатели как раз и писали эти модули в расчете на подобные пазлы 🙂
      Вот был бы еще модуль, чтобы для синхронного канала ответное сообщение сформировать – вообще бы сказка была.

      Reply
  2. Екатерина

    Добрый день! Спасибо большое за информативную статью!
    Буду очень благодарна, если проясните один момент. При настройке канала отправителя ответа у вас сказано: “Будем считать, что система выдает ответ в другую директорию в виде XML-файла. Имя этого файла — все тот же GUID исходного запроса.”. При этом имя читаемого файла у вас обозначено *, то есть брать из директории ответа все файлы, я правильно понимаю? А что делать, если в этой директории в это же время лежат еще и другие файлы с ответами? То есть как прочитать только тот файл ответа, имя которого равно нашему номеру исходного сообщения?
    Большое спасибо!

    Reply
    1. pitroff.ru Post author

      Екатерина, здравствуйте!

      Это делается модулем DynamicConfigurationBean, его настройки на рисунке 12 и чуть ниже:

      Используя стандартный модуль DynamicConfigurationBean мы записываем имя файла в заголовок PI сообщения, в параметр correlationId — то есть заполняем корреляцию для дальнейшей обработки ответа.

      Поскольку мы в настройках разрешили динамически конфигурировать имя файла (рис.11, в самом низу), а модуль DynamicConfigurationBean будет вызван ДО чтения файла – то в заголовке сообщения в результате появится динамически настроенное имя файла – корреляция из заголовка сообщения.
      А далее модуль NotifyResponseBean прочитает файл с уже заданным именем и отправит его содержимое обратно по мосту.

      Reply
      1. Екатерина

        Добрый день! Спасибо большое за ответ!
        Я сомневалась, что этих настроек хватает, поскольку сделала все точно так же, как описано, но в итоге у меня каналом-отправителем читаются все файлы из папки. Не подскажете, может ли быть такая проблема из-за того, что у меня SFTP-адаптер (не seeburger, а отдельно поставляемый SAP) в канале-отправителе?
        Спасибо!

        Reply
        1. Екатерина

          Нет, проверила на FTP-отправителе, все равно берет все подряд файлы. Несмотря на то, что ASMA настроено и модули прописаны…

          Reply
          1. pitroff.ru Post author

            Возможные ошибки:

            1) Посмотрите ключи и имена модулей – возможна ошибка в регистре символа или написании имени модуля.
            2) Посмотрите в мониторе сообщений, что в возвращаемом сообщении в заголовке, в части DynamicConfiguration – отработал ли модуль и занес ли значение в заголовок.
            3) Посмотрите лог обработки через Message Monitoring – там видно, как отрабатывают модули, возможно, там ошибка.

            Может, конечно, и адаптер “чудить” – я SFTP в такой конфигурации не настраивал, чтобы пример не усложнять.

            Reply

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *