Saga Pattern یا دیزاین پترن ساگا، الگوی مدیریت یک فرایند تجاری چندمرحله‌ای در سیستم توزیع‌شده است. تفاوت کلیدی آن با تراکنش تک‌دیتابیسی، Commit شدن مستقل هر مرحله است. بنابراین هنگام شکست، هماهنگ‌کننده یا سرویس‌ها باید اقدام‌های جبرانی را شروع کنند، نه اینکه انتظار Rollback خودکار میان همه دیتابیس‌ها را داشته باشند.

طراحی ساگا از صفر

مرحلهعملیات اصلیعملیات جبرانی احتمالی
۱رزرو موجودی سفارشآزاد کردن موجودی رزروشده
۲گرفتن پرداختبازپرداخت یا Void کردن پرداخت، بسته به وضعیت درگاه
۳ثبت مرسولهلغو درخواست ارسال، در صورت امکان

ساگا مبتنی بر رویداد یا هماهنگ‌کننده؟

در Orchestration یک هماهنگ‌کننده مرکزی، وضعیت مراحل را نگه می‌دارد و فرمان مرحله بعد را ارسال می‌کند. در Choreography هر سرویس به رویداد سرویس قبلی گوش می‌دهد و بدون هماهنگ‌کننده مرکزی پیش می‌رود. روش اول مشاهده و عیب‌یابی جریان‌های طولانی را آسان‌تر می‌کند، روش دوم وابستگی به یک هماهنگ‌کننده مشترک را کاهش می‌دهد، ولی با زیاد شدن رویدادها پیچیده می‌شود.

شبه‌کد مدیریت شکست

# Educational pseudocode: each action calls a real service API.
def place_order(order_id):
    compensated = []
    try:
        inventory.reserve(order_id)
        compensated.append(lambda: inventory.release(order_id))

        payment.charge(order_id)
        compensated.append(lambda: payment.refund(order_id))

        delivery.schedule(order_id)
        return "confirmed"
    except ServiceError:
        for compensate in reversed(compensated):
            enqueue_with_retry(compensate)  # never silently ignore errors
        return "compensation_pending"

پرسش‌های ضروری پیش از اجرای ساگا

پرسشپاسخ قابل قبول در طراحی
اگر رویداد دوبار دریافت شد؟کلید یکتا و عملیات آیدمپوتنت
اگر سرویس پرداخت Timeout شد؟بررسی وضعیت تراکنش با شناسه درخواست، نه کسر وجه مجدد
اگر جبران شکست خورد؟Retry با Backoff، ثبت خطا و مسیر رسیدگی انسانی
اگر هم‌زمان دو خرید از آخرین کالا رخ داد؟کنترل هم‌زمانی در سرویس موجودی
اگر سرویس هماهنگ‌کننده ری‌استارت شد؟Persist کردن وضعیت ساگا و ادامه از آخرین گام معتبر

این شبه‌کد فقط منطق تصمیم‌گیری را نمایش می‌دهد. در محیط واقعی، وضعیت ساگا و شناسه همبستگی باید پایدار ذخیره شوند، اقدام‌های جبرانی در صف پردازش شوند و پس از ری‌استارت نیز ادامه پیدا کنند. از الگوی صندوق خروجی تراکنشی برای هماهنگی ثبت داده و ارسال رویداد کمک می‌گیرند. هر مرحله باید آیدمپوتنسی باشد تا اجرای دوباره پیام باعث دوبار کسر وجه یا دوبار رزرو نشود.

نکته معماری

این الگو را برای هر عملیات ساده انتخاب نکنید. اگر همه تغییرات در یک دیتابیس انجام می‌شوند، تراکنش ACID ساده‌تر و مطمئن‌تر است.

اصطلاحات فنی: ساگا، اسید، میکروسرویس، مسیج بروکر، الگوی صندوق خروجی تراکنشی.