نویسنده در database خود ۱۱ سفارش پیدا کرده بود که چند روز در وضعیت pending مانده بودند، درحالیکه مشتریها پرداخت کرده بودند. مشکل از سرویس پرداخت نبود: برنامه بین موفقیت پرداخت و ثبت وضعیت paid متوقف شده بود. آموزش، راهحلی با Python و standard library برای اصلاح این وضعیت نشان میدهد.
در function اولیه، ابتدا درخواست برداشت پول به سرویس پرداخت فرستاده میشود و سپس وضعیت سفارش در database تغییر میکند. اگر برنامه بین این دو مرحله متوقف شود، زمان درخواست تمام شود یا برنامه دوباره راهاندازی شود، پول جابهجا شده اما سفارش همچنان pending است. اجرای دوباره کل function هم میتواند باعث برداشت دوباره از مشتری شود؛ انجام ندادن کاری نیز سفارش را معطل نگه میدارد.
بخش اول راهحل، استفاده از Idempotency Key است: هر پرداخت منطقی باید کلیدی داشته باشد که در تلاشهای دوباره تغییر نکند. نمونه با ترکیب شناسه سفارش و مبلغ به سنت، محاسبه SHA-256 و برداشتن ۳۲ نویسه اول نتیجه، این کلید را میسازد. کلید همراه درخواست پرداخت ارسال میشود تا تکرار درخواست با همان کلید، نتیجه اصلی را برگرداند، نه اینکه پرداخت تازهای انجام دهد. متن به مستندات Stripe برای این رفتار اشاره میکند.
بخش دوم، یک Reconciliation Job است که هر چند دقیقه اجرا میشود. در نمونه، فقط سفارشهایی بررسی میشوند که بیش از ۱۵ دقیقه از ایجادشان گذشته و هنوز pending هستند. برنامه با کلید ذخیرهشده از سرویس پرداخت استعلام میگیرد. اگر نتیجهای پیدا نشود، وضعیت را failed میکند؛ اگر پرداخت انجام شده باشد، وضعیت را paid میکند. در پایان نیز تغییرها در database ثبت میشوند.
نویسنده سه قاعده برای این کار مطرح میکند: سفارشهای تازه بررسی نشوند تا با درخواست در حال اجرا تداخل پیش نیاید؛ نتیجه سرویس پرداخت مبنا باشد، نه حدس محلی؛ و خود job هم idempotent باشد، یعنی اجرای دوبارهاش همان نتیجه را بدهد. ثبت log برای هر سفارش اصلاحشده و هشدار در صورت باقیماندن سفارشهای قدیمی برای بیش از یک ساعت، پیشنهادهای مرحله بعد هستند، نه بخشهای پیادهسازیشده نمونه.




