پرداخت با Python؛ اصلاح سفارش‌هایی که در pending گیر می‌کنند

چرا مهم است

اگر با پرداخت کار می‌کنی، موفقیت برداشت پول لزوماً به معنی ثبت وضعیت سفارش نیست. این نمونه نشان می‌دهد چرا تکرار کامل درخواست می‌تواند برداشت دوباره ایجاد کند و چرا سفارش‌های pending به بررسی جداگانه نیاز دارند.

قبل از خواندن، این‌ها را بدان۴ مفهوم
idempotent

ویژگی عملیاتی که اجرای چندباره آن، همان اثر اجرای یک‌باره را دارد.

بیشتر: idempotent

standard library

مجموعه ابزارها و module‌هایی که همراه یک زبان برنامه‌نویسی ارائه می‌شوند و برای استفاده از آن‌ها نیازی به نصب بسته جداگانه نیست.

بیشتر: standard library

Idempotency Key

کلیدی ثابت برای شناسایی یک عملیات منطقی که به سرویس امکان می‌دهد درخواست تکراری را تشخیص دهد و به‌جای انجام دوباره عملیات، نتیجه قبلی را برگرداند.

در حال نگارش: Idempotency Key

Reconciliation Job

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

در حال نگارش: Reconciliation Job

نویسنده در database خود ۱۱ سفارش پیدا کرده بود که چند روز در وضعیت pending مانده بودند، درحالی‌که مشتری‌ها پرداخت کرده بودند. مشکل از سرویس پرداخت نبود: برنامه بین موفقیت پرداخت و ثبت وضعیت paid متوقف شده بود. آموزش، راه‌حلی با Python و standard library برای اصلاح این وضعیت نشان می‌دهد.

در function اولیه، ابتدا درخواست برداشت پول به سرویس پرداخت فرستاده می‌شود و سپس وضعیت سفارش در database تغییر می‌کند. اگر برنامه بین این دو مرحله متوقف شود، زمان درخواست تمام شود یا برنامه دوباره راه‌اندازی شود، پول جابه‌جا شده اما سفارش همچنان pending است. اجرای دوباره کل function هم می‌تواند باعث برداشت دوباره از مشتری شود؛ انجام ندادن کاری نیز سفارش را معطل نگه می‌دارد.

بخش اول راه‌حل، استفاده از Idempotency Key است: هر پرداخت منطقی باید کلیدی داشته باشد که در تلاش‌های دوباره تغییر نکند. نمونه با ترکیب شناسه سفارش و مبلغ به سنت، محاسبه SHA-256 و برداشتن ۳۲ نویسه اول نتیجه، این کلید را می‌سازد. کلید همراه درخواست پرداخت ارسال می‌شود تا تکرار درخواست با همان کلید، نتیجه اصلی را برگرداند، نه اینکه پرداخت تازه‌ای انجام دهد. متن به مستندات Stripe برای این رفتار اشاره می‌کند.

بخش دوم، یک Reconciliation Job است که هر چند دقیقه اجرا می‌شود. در نمونه، فقط سفارش‌هایی بررسی می‌شوند که بیش از ۱۵ دقیقه از ایجادشان گذشته و هنوز pending هستند. برنامه با کلید ذخیره‌شده از سرویس پرداخت استعلام می‌گیرد. اگر نتیجه‌ای پیدا نشود، وضعیت را failed می‌کند؛ اگر پرداخت انجام شده باشد، وضعیت را paid می‌کند. در پایان نیز تغییرها در database ثبت می‌شوند.

نویسنده سه قاعده برای این کار مطرح می‌کند: سفارش‌های تازه بررسی نشوند تا با درخواست در حال اجرا تداخل پیش نیاید؛ نتیجه سرویس پرداخت مبنا باشد، نه حدس محلی؛ و خود job هم idempotent باشد، یعنی اجرای دوباره‌اش همان نتیجه را بدهد. ثبت log برای هر سفارش اصلاح‌شده و هشدار در صورت باقی‌ماندن سفارش‌های قدیمی برای بیش از یک ساعت، پیشنهادهای مرحله بعد هستند، نه بخش‌های پیاده‌سازی‌شده نمونه.

نکته کلیدی

برای هر پرداخت منطقی، کلیدی ثابت در تلاش‌های دوباره نگه دار. سفارش‌های pending قدیمی را با نتیجه سرویس پرداخت تطبیق بده و job را طوری بنویس که اجرای دوباره‌اش همان نتیجه را داشته باشد.

خواندن مقاله اصلی (در زبانه‌ی جدید باز می‌شود)
برچسب‌ها (۴)