🛰 پیامرسانی Request-Response با MassTransit
کتابخانهی MassTransit بهصورت پیشفرض از الگوی پیامرسانی Request-Response پشتیبانی میکند.
ما میتوانیم از یک Request Client برای ارسال درخواستها و انتظار برای پاسخ استفاده کنیم.
این Request Client بهصورت asynchronous است و از کلیدواژهی await پشتیبانی میکند.
بهصورت پیشفرض، درخواست دارای timeout سیثانیهای است تا از انتظار بیشازحد برای پاسخ جلوگیری شود.
بیایید یک سناریو را تصور کنیم که در آن سیستمی برای پردازش سفارش دارید و باید آخرین وضعیت یک سفارش را بازیابی کنید.
ما میتوانیم وضعیت را از سرویس Order Management دریافت کنیم.
با MassTransit، شما یک Request Client ایجاد میکنید تا این فرآیند را آغاز کند.
این کلاینت پیامی از نوع GetOrderStatusRequest را روی bus ارسال میکند.
public record GetOrderStatusRequest
{
public string OrderId { get; init; }
}
در سمت Order Management، یک responder (یا consumer) در حال گوش دادن به پیامهای GetOrderStatusRequest است.
این consumer درخواست را دریافت میکند، احتمالاً به پایگاه داده کوئری میزند تا وضعیت را بگیرد، و سپس پیامی از نوع GetOrderStatusResponse را دوباره روی bus ارسال میکند.
کلاینت درخواستدهنده در انتظار این پاسخ خواهد بود و میتواند آن را مطابق نیاز پردازش کند.
public class GetOrderStatusRequestConsumer : IConsumer<GetOrderStatusRequest>
{
public async Task Consume(ConsumeContext<GetOrderStatusRequest> context)
{
// Get the order status from a database.
await context.ResponseAsync<GetOrderStatusResponse>(new
{
// Set the respective response properties.
});
}
}
👥 دریافت سطح دسترسی کاربران در Modular Monolith
در اینجا یک سناریوی واقعی وجود دارد که تیم ما تصمیم گرفت این الگو را پیادهسازی کند.
ما در حال ساخت یک modular monolith بودیم و یکی از ماژولها مسئول مدیریت user permissions بود.
سایر ماژولها میتوانستند برای دریافت سطح دسترسی کاربر به ماژول Users فراخوانی انجام دهند.
و این تا زمانی که داخل یک سیستم monolith هستیم بهخوبی کار میکند.
اما در مقطعی نیاز داشتیم یکی از ماژولها را به یک سرویس مجزا استخراج کنیم.
این بدان معنا بود که ارتباط با ماژول Users از طریق method callهای ساده دیگر کار نخواهد کرد.
خوشبختانه، ما از قبل از MassTransit و RabbitMQ برای پیامرسانی درون سیستم استفاده میکردیم.
بنابراین تصمیم گرفتیم از قابلیت request-response در MassTransit برای پیادهسازی این ارتباط استفاده کنیم.
سرویس جدید یک <IRequestClient<GetUserPermissions تزریق میکند.
ما میتوانیم از آن برای ارسال پیام GetUserPermissions و انتظار برای پاسخ استفاده کنیم.
یکی از ویژگیهای قدرتمند MassTransit این است که میتوانید منتظر بیش از یک نوع پاسخ باشید.
در این مثال، ما منتظر PermissionsResponse یا Error هستیم.
این عالی است، چون راهی برای مدیریت خطاها در consumer نیز داریم.
internal sealed class PermissionService(
IRequestClient<GetUserPermissions> client)
: IPermissionService
{
public async Task<Result<PermissionsResponse>> GetUserPermissionsAsync(
string identityId)
{
var request = new GetUserPermissions(identityId);
Response<PermissionsResponse, Error> response =
await client.GetResponse<PermissionsResponse, Error>(request);
if (response.Is(out Response<Error> errorResponse))
{
return Result.Failure<PermissionsResponse>(errorResponse.Message);
}
if (response.Is(out Response<PermissionsResponse> permissionResponse))
{
return permissionResponse.Message;
}
return Result.Failure<PermissionsResponse>(NotFound);
}
}