المستوى: متوسط (Intermediate) — محتاج تكون مرتاح في Node.js وExpress وعندك فكرة أساسية عن SQL. مش محتاج خبرة سابقة في الـ webhooks.
اعمل Webhook Receiver يمنع الدفع المزدوج
في آخر المقال هيبقى عندك نقطة استقبال webhook بتنفّذ كل حدث مرة واحدة بالظبط، حتى لو بوابة الدفع بعتتهولك خمس مرات. كله في جدول واحد و70 سطر كود.
المشكلة باختصار
بوابات الدفع زي Stripe و PayPal بتبعتلك webhook لما يحصل حدث: عملية دفع نجحت، اشتراك اتجدّد، استرجاع اتعمل. القاعدة عندهم بسيطة: لو السيرفر بتاعك ماردش بـ 200 بسرعة، يعتبروا إن الرسالة ضاعت ويبعتوها تاني. Stripe بالتحديد بيفضل يعيد المحاولة لمدة توصل 3 أيام لو ماجاش رد ناجح.
النتيجة اللي بتحصل فعلاً: نفس حدث الدفع بيوصلك مرتين أو تلاتة. لو الكود بتاعك بيعمل fulfillOrder() أو بيبعت إيصال أو بيضيف رصيد في كل مرة، يبقى العميل اتحاسب مرتين أو استلم منتجه مرتين. ده مش سيناريو نظري؛ ده بيحصل تحت الحمل العادي لمّا السيرفر يتأخّر شوية في الرد.
إيه هي الـ Idempotency أصلاً؟
تخيّل زرار الأسانسير. لو دُست عليه مرة، أو خمس مرات بعصبية، الأسانسير هييجي مرة واحدة. الضغطة الزيادة مالهاش أي تأثير إضافي. ده بالظبط معنى idempotency.
علميًا: العملية بتكون idempotent لو تنفيذها مرة واحدة بيدّي نفس النتيجة بالظبط زي تنفيذها عدة مرات بنفس المدخلات. GET في HTTP idempotent بطبيعته. لكن "نفّذ عملية الدفع" مش idempotent بطبيعتها — لو نفّذتها مرتين، اتحاسب مرتين. شغلتنا هنا إننا نخلّيها idempotent بإيدينا.
الحيلة: كل حدث جاي من بوابة الدفع بيكون معاه معرّف فريد ثابت (event.id في Stripe). ده الـ idempotency key. لو شُفت نفس الـ id قبل كده، تتجاهله ببساطة.
ليه القيد الفريد في الداتابيز أأمن من الفحص اليدوي
أول فكرة بتيجي للناس: "هاعمل SELECT أشوف الحدث موجود ولا لأ، وبعدين أعالجه." الطريقة دي بتفشل تحت التزامن (concurrency). لو وصلك نسختين من نفس الحدث في نفس اللحظة، الاتنين هيعملوا SELECT ويلاقوه مش موجود، فالاتنين هيعالجوا. ده race condition كلاسيكي.
بدل ما تعتمد على الفحص اليدوي، خلّي الداتابيز نفسها تفرض التفرّد. عمود PRIMARY KEY على معرّف الحدث معناه إن محاولة إدخال نفس الـ id تاني هتفشل ذرّيًا (atomically) على مستوى المحرّك. ده خط الدفاع الحقيقي.
ابنيها في 6 خطوات
- اعمل جدول لتخزين الأحداث المعالَجة. عمود واحد فريد كفاية.
- تحقّق من توقيع الـ webhook علشان متعالجش طلب مزوّر من حد بيتظاهر إنه Stripe.