Обмен Сообщениями с Помощью MassTransit
Создание распределённых приложений – дело непростое. Есть ряд потенциальных проблем, которые необходимо учитывать. Что делать, если в сети произошел сбой или сервис неожиданно прекратил работу? Способ взаимодействия частей распределённой системы становится критически важным.
Синхронная связь, когда сервисы напрямую обращаются друг к другу, хрупка. Она создаёт тесную связь, делая всё приложение уязвимым для отдельных точек отказа. Мы можем использовать распределённый обмен сообщениями. Одна из известных утилит для этого в мире .NET – MassTransit.
Шаблон обмена сообщениями запрос-ответ
Шаблон запрос-ответ аналогичен традиционному вызову функции, но по сети. Одна служба, запрашивающая сторона, отправляет сообщение запроса и ожидает соответствующего ответного сообщения.
Достоинства
1. Слабая связь: сервисам не требуются знания друг о друге, а только контракты сообщений. Это упрощает внесение изменений и масштабирование.
2. Прозрачность местоположения: запрашивающей стороне не нужно знать, где находится отвечающая сторона, что обеспечивает повышенную гибкость.
Недостатки
1. Задержка: накладные расходы на обмен сообщениями добавляют дополнительную задержку.
2. Сложность: внедрение системы обмена сообщениями и управление дополнительной инфраструктурой могут повысить сложность проекта.
MassTransit поддерживает шаблон запрос-ответ «из коробки». Мы можем использовать клиент запросов для отправки запросов и ожидания ответа. Клиент запроса является асинхронным. По умолчанию запрос также будет иметь тайм-аут 30 секунд, чтобы не допустить слишком длительного ожидания ответа.
Например, у нас система обработки заказов и необходимо получить статус заказа из сервиса управления заказами. С помощью MassTransit создадим клиента, реализующего
IRequestClient<T>, для инициирования запроса:public class RequestController :
Controller
{
IRequestClient<StatusRequest> _client;
…
public async Task<IActionResult>
Get(string id, CancellationToken ct)
{
var response = await
_client.GetResponse<StatusResponse>(
new { id }, ct);
return Ok(response.Message);
}
}
Он отправит на шину сообщение GetOrderStatusRequest:
public record StatusRequest(string OrderId);
И будет ожидать ответа:
public record StatusResponse(
string OrderId,
short StatusCode,
string StatusText
}
В сервисе управления заказами ответчик (
IConsumer<T>) будет прослушивать сообщения StatusRequest. Он получает запрос, возможно запрашивает БД и отправляет сообщение StatusResponse обратно на шину. Клиент будет ждать этого ответа и затем сможет обработать его соответствующим образом:public class StatusRequestConsumer :
IConsumer<StatusRequest>
{
public async Task Consume(
ConsumeContext<StatusRequest> ctx)
{
…
await ctx
.RespondAsync<StatusResponse>(new
{
// задаём свойства ответа
});
}
}
Полный код примера есть в документации MassTransit.
Итого
Шаблон запрос-ответ — мощный инструмент при обмене сообщениями между сервисами. MassTransit значительно упрощает реализацию, гарантируя надежную доставку запросов и ответов.
Мы можем использовать запрос-ответ для реализации связи между модулями в модульном монолите. Однако не стоит доводить это до крайности, иначе система может страдать от увеличения задержки.
Источник: https://www.milanjovanovic.tech/blog/request-response-messaging-pattern-with-masstransit