Шаблон проектирования 3. Что такое шаблон «запрос-ответ» и как его использовать?

Это третья статья из серии о шаблонах проектирования. Каждая статья будет посвящена одному паттерну, описывая, что это такое и какую проблему он решает.

Проблема

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

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

Как это решить

Сначала я кратко опишу разницу между синхронной и асинхронной связью. Ниже показано, что машина A ожидает обработки запроса машиной B.

Проблема с синхронной связью заключается в том, что если машина B не работает, например, во время развертывания или обслуживания, запросы от машины A к машине B не будут выполнены. Это означает, что клиенты, инициирующие операции создания заказов через машину A, также не будут работать.

Чтобы избежать жесткой связи с машиной B, вместо этого можно ввести асинхронную связь. На рисунке 2 ниже мы видим, что вместо того, чтобы машина A взаимодействовала напрямую с машиной B, она загружает сообщение в CreateOrderQueue. Когда машина B готова, она берет и обрабатывает сообщения в очереди. Важной частью здесь является то, что работа машины А выполняется, как только она загрузит сообщение. Ему все равно, когда сообщение будет обработано и пройдет ли оно хорошо.

Но что, если машине А потребуется результат от машины Б после того, как она обработает сообщение о создании заказа? Может случиться так, что машина А хочет обновить локальный статус заказа, который будет создан, или потерпит неудачу, в зависимости от результата обработки машиной Б. Здесь на сцену выходит схема «запрос-ответ».

На приведенной ниже иллюстрации происходит несколько вещей, но позвольте мне объяснить последовательность действий. Клиент отправляет запрос POST на машину A для создания заказа. Машина А вставляет новый заказ в свою локальную базу данных со статусом «в обработке», вероятно, после некоторой проверки, которая здесь не учтена. После вставки статуса заказа он создает CreateOrderRequestMsg, который загружается в CreateOrderRequestQueue, после чего ответ отправляется клиенту. Клиент получает ответ до того, как заказ будет обработан.

Затем машина B берет сообщение запроса из очереди запросов и обрабатывает его, в данном случае просто вставляя его в базу данных. После обработки сообщения создается сообщение CreateOrderReplyMsg, содержащее идентификатор и статус заказа, и загружается в очередь CreateOrderReplyQueue. Затем это сообщение принимается машиной А и обновляет статус заказа на основе содержания сообщения. Машина A также предоставляет конечную точку GET OrderStatus, чтобы клиент мог проверить статус заказа.

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

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

{OPERATION_NAME}Очередь запросов

{OPERATION_NAME}ЗапросMsg

{OPERATION_NAME}Очередь ответов

{OPERATION_NAME}ОтветитьСообщение

Заключение

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

Существует широкий спектр шаблонов обмена сообщениями, разработанных для различных сценариев, и в будущем я расскажу о некоторых из них, так что следите за обновлениями!

Больше контента на plainenglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку здесь.