در سیستم های توضیع شده وقتی دو برنامه (اپلیشن/سرویس) نیاز به سازگاری (consistency) ۱۰۰٪ی دارند. می بایست بتوانند با قابلیت اطمینان بالا ارسال اطلاعات را انجام دهند. در این مقاله یک مثال ساده را به کار خواهیم گرفت تا این پترن را با هم بهتر درک کنیم. در این مقاله فرض شده دو سرویس داریم یکی مسئول مدیریت کاربران و دیگری مسئول ارسال نوتیفیکشن. وقتی در وضعیت کاربری از حالت Inactive به Active تغییر کند سرویس نوتیفیکشن فرخوانده خواهد شد.
کدهای مربوط به این پروژه در گیت هاب قابل دسترس است.
پترن Transactional Outbox روشی مطمئن برای انتشار رویدادهای دامنه است؛ روشی که از گمشدن رویدادها پس از ثبت موفق تراکنش پایگاه داده جلوگیری میکند.
در یک روند معمول، ممکن است اطلاعات کاربر با موفقیت ذخیره شود، اما ارسال اعلان یا انتشار رویداد خارجی شکست بخورد. در نتیجه، پایگاه داده و سرویسهای جانبی از یکدیگر جدا میشوند. الگوی Outbox این مشکل را با ذخیرهکردن رویداد در همان تراکنش تغییر اصلی حل میکند. سپس یک پردازشگر پسزمینه، رویدادهای ذخیرهشده را بهصورت غیرهمزمان پردازش میکند.
این پروژه از معماری پیازی (Onion Architecture) پیروی میکند. مدل دامنه در مرکز قرار دارد، سرویسهای application موارد کاربرد را هماهنگ میکنند و زیرساختهایی مانند پایگاه داده، HTTP و jobهای زمانبندیشده در لایه بیرونی قرار میگیرند. وابستگیها همیشه به سمت مرکز هستند؛ بنابراین دامنه اصلی به فریمورکها و جزئیات فنی وابسته نیست.
دامنه کاربر شامل aggregate مربوط به User و رویدادهایی مانند موارد زیر است:
UserCreatedEvent
UserUpdatedEvent
UserStatusChangedEvent
هر کاربر دارای فیلدهایی مانند نام کاربری، نام، نام خانوادگی و وضعیت ACTIVE یا INACTIVE است. هنگام ایجاد یا بهروزرسانی کاربر، aggregate بهجای اجرای مستقیم side effectها، رویداد دامنه را ثبت میکند.
دامنه نوتیفیکیشن مسئول واکنش به تغییرات مهم کسبوکار است. در این مثال، هنگامی که وضعیت کاربر از INACTIVE به ACTIVE تغییر کند، یک اعلان فعالسازی ثبت میشود.
این دامنه از دامنه کاربر جداست و در جریان تراکنش بهروزرسانی کاربر مستقیماً فراخوانی نمیشود؛ بلکه بعداً توسط پردازشگر Outbox اجرا میشود.
ایجاد یا بهروزرسانی کاربر در یک تراکنش انجام میشود.
aggregate رویداد دامنه تولید میکند.
سرویس application، اطلاعات کاربر و رویداد Outbox را در همان تراکنش ذخیره میکند.
هر دو مورد با هم commit میشوند.
UserOutboxEventPublisher رویدادهای پردازشنشده را پیدا میکند.
اگر رویداد از نوع UserStatusChangedEvent باشد، تغییر وضعیت بررسی میشود.
در صورت تغییر از INACTIVE به ACTIVE، سرویس اعلان فراخوانی شده و اعلان در repository ثبت میشود.
به این ترتیب، تراکنش اصلی اتمیک باقی میماند و side effectها در مرحلهای قابلاعتماد و غیرهمزمان اجرا میشوند.