پردازش Outbox ⚙️
پردازشگر Outbox کامپوننت بعدی است که به آن نیاز داریم. این میتواند یک فرآیند فیزیکی جداگانه یا یک background worker در همان فرآیند باشد.
من از Quartz برای زمانبندی background jobها برای پردازش Outbox استفاده خواهم کرد.
[DisallowConcurrentExecution]
public class OutboxProcessorJob(...) : IJob
{
public async Task Execute(IJobExecutionContext context)
{
// پیامهای پردازش نشده را از دیتابیس واکشی میکند
var messages = await connection.QueryAsync<OutboxMessage>(...);
foreach (var message in messages)
{
try
{
// پیام را deserialize کرده و به message broker منتشر میکند
await publishEndpoint.Publish(deserializedMessage);
// پیام را به عنوان پردازش شده علامتگذاری میکند
await connection.ExecuteAsync(
"UPDATE outbox_messages SET processed_on_utc = @ProcessedOnUtc WHERE id = @Id",
...);
}
catch (Exception ex)
{
// خطا را لاگ میکند
}
}
await transaction.CommitAsync();
}
}
یک راه جایگزین برای پردازش پیامهای Outbox، استفاده از Transaction log tailing است. ما میتوانیم این را با استفاده از Postgres logical replication پیادهسازی کنیم.
ملاحظات و مزایا و معایب 🧐
الگوی Outbox، ضمن کارآمدی، پیچیدگی و نوشتنهای اضافی در دیتابیس را به همراه دارد.
🔹 توصیه میکنم مکانیزمهای تلاش مجدد (retry) را در پردازشگر Outbox برای بهبود قابلیت اطمینان پیادهسازی کنید.
🔹 ضروری است که مصرفکنندگان پیام idempotent را پیادهسازی کنید.
🔹 با گذشت زمان، جدول Outbox میتواند به طور قابل توجهی رشد کند. مهم است که یک استراتژی آرشیو از همان ابتدا پیادهسازی کنید.
مقیاسپذیری پردازش Outbox 🚀
با رشد سیستم شما، ممکن است یک پردازشگر Outbox نتواند حجم پیامها را مدیریت کند.
🔹 یک رویکرد ساده، افزایش فرکانس اجرای job پردازشگر Outbox است.
🔹 یک استراتژی مؤثر دیگر، افزایش اندازه بچ (batch size) هنگام واکشی پیامهای پردازش نشده است.
🔹 برای سیستمهای با حجم بالا، پردازش Outbox به صورت موازی میتواند بسیار مؤثر باشد. یک مکانیزم قفلگذاری برای ادعای بچهای پیام پیادهسازی کنید.
جمعبندی ✅
الگوی Outbox یک ابزار قدرتمند برای حفظ سازگاری داده در سیستمهای توزیعشده است. با جداسازی عملیات دیتابیس از انتشار پیام، الگوی Outbox تضمین میکند که سیستم شما حتی در مواجهه با شکستها، قابل اعتماد باقی بماند.
به یاد داشته باشید که مصرفکنندگان خود را idempotent نگه دارید، استراتژیهای مقیاسپذیری مناسب را پیادهسازی کنید، و رشد جدول Outbox خود را مدیریت کنید.
🔖 هشتگها:
#SoftwareArchitecture #SystemDesign #Microservices #DistributedSystems #OutboxPattern #EventDrivenArchitecture #DataConsistency
🧠 جمعبندی
Domain Event
ها به شما کمک میکنند تا سیستمی loosely coupled بسازید.
میتوانید از آنها برای جدا کردن منطق اصلی دامنه از اثرات جانبی (side effects) استفاده کنید،
اثراتی که میتوانند به صورت asynchronous مدیریت شوند.
لازم نیست برای پیادهسازی Domain Eventها از صفر شروع کنید؛
میتوانید از ترکیب EF Core و MediatR استفاده کنید تا این قابلیت را بهسادگی بسازید.
باید تصمیم بگیرید که چه زمانی میخواهید Domain Eventها را منتشر کنید:
قبل یا بعد از ذخیره شدن تغییرات در پایگاه داده — هرکدام مزایا و معایب خاص خود را دارند.
من شخصاً ترجیح میدهم بعد از ذخیرهسازی تغییرات Domain Eventها را منتشر کنم
و برای اطمینان از تراکنش اتمیک، از الگوی Outbox استفاده میکنم.
این رویکرد باعث ایجاد eventual consistency میشود،
اما در عین حال قابل اعتمادتر است.
امیدوارم این مطلب برایتان مفید بوده باشد 🙌
🔖هشتگها:
#DomainEvents #EFCore #OutboxPattern #EventDriven #DesignPatterns #LooselyCoupled