در این پست به این سوالات پاسخ میدم :
1- الگوی Outbox چه مشکلی رو حل می کنه ؟
2- الگوی Outbox چطور پیاده سازی میشه ؟
3- چالش های این الگو چیه؟
4- یک مثال کاربردی از Outbox
در معماری میکروسرویس یا هر معماری ای که ارتباط بین سرویس ها براساس پیام هایی روی Message Broker ها (مانند RabbitMq یا Kafka) باشد ، معمولا سرویس فرستنده پیام ، همزمان با ارسال پیام بایستی دیتاهایی در دیتابیس خود نیز ثبت کند که این فرآیند به چند صورت قابل انجام است :
مشکل این روش این است که ممکن است اطلاعات با موفقیت ذخیره شود ولی ارسال پیام با موفقیت انجام نشود (مثلا اتصال به Message Broker انجام نشود یا ..) . بنابراین سرویس گیرنده پیام از انجام تراکنش بی خبر است و بخشی از عملیات مورد نظر انجام نخواهد شد .
مشکل این روش برعکس روش قبلی است یعنی ممکن است پیام ارسال شود ولی اطلاعات با موفقیت ذخیره نشود (مثلا اتصال به دیتابیس انجام نشود یا ..) . بنابراین سرویس گیرنده پیام ، پیام اشتباه دریافت خواهد کرد و ممکن است در فرآیند کاری سیستم اختلال ایجاد شود ، مشکل دیگر این روش این است که حتی اگر هر دو عملیات موفقیت آمیز انجام شود ممکن است ذخیره سازی اطلاعات در دیتابیس کمی طول بکشد و در این فاصله ، سرویس گیرنده پیام را دریافت و پردازش کند و ترتیب اجرای عملیات با مشکل مواجه شود .
مشکل این روش این است که توسط برخی از دیتابیس ها پشتیبانی نمی شود .
این روش موضوع این مقاله است و مشکلات روش های قبلی را ندارد و اصطلاحا atomically عملیات ذخیره اطلاعات و ارسال پیام را انجام می دهد .
با این روش ، مطمئن هستیم که پیام بعد از ذخیره سازی موفق دیتا ، ارسال خواهد شد و ضمنا مطمئن هستیم که پیام ارسال خواهد شد .
اگر ذخیره سازی اطلاعات با مشکل مواجه شود پیام ها نیز در جدول outbox ذخیره نخواهند شد (به دلیل اینکه کل اطلاعات با یک تراکنش به دیتابیس ارسال شده است) .
اگر ارسال پیام ها به Message Broker با مشکل مواجه شود ، مجددا چند ثانیه دیگر برای ارسال تلاش خواهد شد و این چرحه تا زمان ارسال موفق پیام ها ادامه پیدا خواهد کرد .
نکته 1 : می توانید به جای حذف پیام ها از جدول Outbox ، یا یک فیلد bit وضعیت ارسال را تغییر دهید ، این راهکار به شما کمک می کند تا سابقه ارسال پیام ها را در دیتابیس داشته باشید .
نکته 2 : برای رعایت ترتیب ارسال پیام ها ، بایستی هنگام ارسال پیام ها را به ترتیب ثبت در جدول واکشی و ارسال کنیم و ضمنا از ارسال موازی پیام ها خودداری کنیم .
تنها مشکل این الگو این است که ممکن است پس از ارسال موفق پیام ، عملیات حذف پیام از جدول outbox با موفقیت انجام نشود .
راهکار این مشکل Idempotent بودن سرویس گیرنده پیام می باشد . یعنی اگر چند بار یک پیام یکسان را دریافت کرد فقط یکبار پردازش انجام دهد .
فرض کنید در یک سایت فروشگاهی بعد از ثبت سفارش بایستی پیامک به خریدار ارسال گردد و سرویس سفارش و پیامک جدا هستند .
کاربر سرویس سفارش را فراخوانی می کند و درخواست ثبت سفارش را ارسال می نمایند سفارش ساخته شده و همزمان با ثبت اطلاعات سفارش ، دستور ارسال پیام به کاربر نیز در قالب یک Message در جدول Outbox ثبت می گردد و پیام "سفارش با موفقیت ثبت شد" به کاربر نمایش داده می شود .
یک سرویس خودکار پیام را از جدول خوانده و به Message Broker ارسال می نماید .
سرویس پیامک ، Message را از Broker دریافت نموده و به خریدار پیام ارسال می کند .