مطالب آموزشی Event Sourcing:
- بخش اول مقدمهای بر Event Sourcing
- بخش دوم آشنایی مقدماتی با ساختار داخلی Event Store
- مقایسه رویکردهای State-Oriented و State-Transition
- مزیتهای Event Sourcing
- سلام به دنیا به روش Event Sourcing
- سلام به دنیا به روش Event Sourcing-بخش دوم
- بخش هفتم Projection
- ویرایش event ها در EventSourcing
- Message، Command یا Event، کدوم رو انتخاب کنم؟
- بخش دهم: Internal Event vs External Event
- بخش یازدهم: Push-Based-vs-Pull-Based
- بخش دوازدهم: مقدمهای بر الگوی Inox-Outbox
مقدمه
در بخش قبلی، به موضوع Push-Based و Pull-Based در ارتباط با پابلیش کردن رویدادها (Events) پرداختیم. در ادامه این سری مقالات، در این بخش به یکی دیگر از الگوهای مهم در Event Sourcing خواهیم پرداخت: الگوی Inbox-Outbox.
این الگو به توسعهدهندگان یک سرویس کمک میکند تا بتوانند eventها را به صورت قابل اطمینان به دنیای بیرون از سرویس خود ارسال کنند. به بیان دیگر مهمترین مزیت و البته دلیل وجودی الگوی Inbox-Outbox تضمین at-least-once-delivery است. Inbox-Outbox الگویی است که برای مدیریت ارتباطات بین سرویسها در معماری مبتنی بر Event Sourcing به کار میرود.
در این الگو، هر سرویس یک صندوق ورودی (Inbox) و یک صندوق خروجی (Outbox) دارد. پیاده سازی این صندوقها میتواند به طرق مختلفی انجام شود. هر سرویس رویدادهایی قصد دارد به دنیای بیرون مخابره کند را ابتدا درون صندوق خروجی(outbox) خود قرار میدهد. این صندوق غالبا بصورت یک صف(Queue) ساده بدون اولویت پیادهسازی میشود. همچنین رویدادهایی که هر سرویس به آنها علاقمند است نیز درون صندوق ورودی آن سرویس نگهداری میشود. این صندوق هم بصورت پیشفرض یک صف(Queue) ساده بدون اولویت پیادهسازی است.
یک سرویس مجزا، پیامها را از صندوق خروجی خوانده، و سپس آنرا به دنیای بیرون مخابره میکند. برای صندوق ورودی نیز سرویس مجزایی وجود دارد، که پیامها را از صندوق ورودی برداشته و آن را پردازش میکند.
این الگو مزایای زیادی دارد که در ادامه به آنها خواهیم پرداخت.
ساختار Inbox-Outbox
همانطور که گفته شد، در این الگو هر سرویس دارای دو صندوق است: Inbox و Outbox. یکی از راهای پیشفرض و ساده پیادهسازی این الگو نگهداری این دو صندوق این دو صندوق به صورت جداگانه در پایگاه داده است.
Outbox: این صندوق محل ذخیره رویدادهایی است که توسط خود سرویس تولید شدهاند. هنگامی که یک رویداد در سرویس ایجاد میشود، ابتدا در Outbox ذخیره میشود. سپس، یک فرایند جداگانه این رویدادها را از Outbox برداشته و به سایر سرویسها ارسال میکند.
Inbox: این صندوق محل ذخیره رویدادهایی است که از سایر سرویسها دریافت شدهاند. این رویدادها پس از دریافت در Inbox ذخیره میشوند و سپس توسط خود سرویس مصرف میشوند.
مزایای الگوی Inbox-Outbox
- قابلیت اطمینان: یکی از مهمترین مزایای این الگو، قابلیت اطمینان آن است. با استفاده از Inbox و Outbox، میتوان اطمینان حاصل کرد که رویدادها به درستی ارسال و دریافت میشوند، حتی در صورت بروز خطا در ارتباطات بین سرویسها.
- مقاوم در برابر شکست: در صورت بروز خطا در ارتباطات بین سرویسها یا در زمان ارسال رویدادها، رویدادها در Outbox ذخیره میشوند و پس از رفع خطا، دوباره ارسال میشوند. این موضوع باعث میشود که سرویسها در برابر شکستهای موقت مقاوم باشند.
- قابلیت بازیابی: در صورت بروز خطا در سرویسها یا سیستمهای مصرفکننده رویدادها، میتوان با بررسی Inbox و Outbox سرویسها، وضعیت سیستم را بازیابی کرد.
- عدم تداخل بین سرویسها: با استفاده از این الگو، هر سرویس مستقل از سایر سرویسها عمل میکند و تغییر در یک سرویس باعث ایجاد مشکل در سایر سرویسها نمیشود.
- امکان بازخورد: در این الگو، سرویسها میتوانند بازخورد دریافت کنند و بر اساس آن رفتار خود را تغییر دهند. به عنوان مثال، یک سرویس میتواند بر اساس بازخورد دریافتی از سرویس مصرفکننده، رویدادهای خود را دوباره ارسال کند.
- امکان تست: با استفاده از این الگو، امکان تست سرویسها به صورت مستقل و بدون نیاز به سایر سرویسها وجود دارد. این امر باعث افزایش قابلیت اطمینان و کاهش هزینههای توسعه و نگهداری میشود.
پیادهسازی Inbox-Outbox
برای پیادهسازی الگوی Inbox-Outbox، نیاز به یک پایگاه داده برای ذخیرهسازی Inbox و Outbox هر سرویس وجود دارد. همچنین، نیاز به یک فرایند جداگانه برای برداشتن رویدادها از Outbox و ارسال آنها به سایر سرویسها وجود دارد.
در زمان ایجاد یک رویداد در یک سرویس، ابتدا آن رویداد در Outbox آن سرویس ذخیره میشود. سپس، فرایند جداگانهای این رویدادها را از Outbox برداشته و به سایر سرویسها ارسال میکند. در سمت گیرنده نیز، رویدادها در Inbox آن سرویس ذخیره میشوند و توسط خود سرویس مصرف میگردند.
در صورت بروز خطا در ارسال رویدادها، آنها در Outbox باقی میمانند تا در زمان مناسب دوباره ارسال شوند. همچنین، در صورت بروز خطا در دریافت روی
public class EventProcessor
{
private readonly List<Event> _inbox = new List<Event>();
private readonly List<Event> _outbox = new List<Event>();
public void ProcessEvent(Event e)
{
// افزودن رویداد به Inbox
_inbox.Add(e);
// پردازش رویداد
ProcessInboxEvents();
// ارسال رویدادهای مربوطه به Outbox
ProcessOutboxEvents();
}
private void ProcessInboxEvents()
{
// پردازش رویدادهای موجود در Inbox
foreach (var inboxEvent in _inbox)
{
// لجیک پردازش رویداد
Console.WriteLine($"Processing event: {inboxEvent.Name}");
// در صورت نیاز به ارسال رویداد، افزودن به Outbox
_outbox.Add(new Event { Name = $"Processed {inboxEvent.Name}" });
}
// پاک کردن Inbox پس از پردازش
_inbox.Clear();
}
private void ProcessOutboxEvents()
{
// ارسال رویدادهای موجود در Outbox
foreach (var outboxEvent in _outbox)
{
// ارسال رویداد به سرویس مربوطه
Console.WriteLine($"Sending event: {outboxEvent.Name}");
}
// پاک کردن Outbox پس از ارسال
_outbox.Clear();
}
}
در این مثال، EventProcessor کلاس مسئول پردازش رویدادها است. هر زمان که یک رویداد جدید دریافت میشود، به Inbox افزوده میشود. سپس، ProcessInboxEvents متد رویدادهای موجود در Inbox را پردازش کرده و در صورت نیاز، به Outbox اضافه میکند. در نهایت، ProcessOutboxEvents متد رویدادهای موجود در Outbox را ارسال میکند.
این راهکار چندین مزیت دارد:
- قابلیت اطمینان: اگر در حین پردازش یا ارسال رویداد، مشکلی پیش آید، رویداد در Inbox یا Outbox باقی میماند تا در آینده دوباره پردازش شود.
- جدایی نگهداری و پردازش: Inbox و Outbox به طور کامل از هم جدا هستند و این امکان را میدهد که پردازش و ارسال رویدادها به صورت مستقل انجام شوند.
- مقیاس پذیری: با افزایش تعداد رویدادها، Inbox و Outbox میتوانند به راحتی گسترش یابند.
- انعطاف پذیری: این پترن امکان تغییر منطق پردازش رویدادها یا ارسال آن ها را بدون تغییر در سایر بخش های سیستم فراهم میکند.
در مجموع، Inbox-Outbox Pattern راهکار مناسبی برای پردازش رویدادها در سیستم های توزیع شده است که به پایداری، انعطاف پذیری و مقیاس پذیری سیستم کمک میکند.
در بخش بعدی، در مورد روشهای مختلف پیادهسازی این الگو و همچنین نحوهی پردازش رویدادهای ورودی و خروجی، اولویت بندی صندوقهای ورودی و خروجی و سایر موارد مهم در این الگو صحبت خواهیم کرد.