قائمة التحقق لـ webhooks الدفع المعاملية لتحديثات فوترة آمنة
قائمة تحقق للويب هوكس المدفوعات المعاملية لإزالة التكرار، التعامل مع إعادة المحاولات، وتحديث الفواتير والاشتراكات والصلاحيات بأمان.

لماذا تولّد webhooks المدفوعات تحديثات مكررة
webhook الدفع هو رسالة يرسلها مزود الدفع إلى الخادم الخلفي عندما يحدث شيء مهم، مثل نجاح الدفع، دفع الفاتورة، تجديد اشتراك، أو صدور استرداد. الفكرة أن المزود يقول: «هذا ما حدث. حدّث سجلاتك.»
تحدث التكرارات لأن تسليم الويب هوكس مصمم ليكون موثوقًا، ليس لمرة واحدة بالضبط. إذا كان خادمك بطيئًا، أو انتهت مهلة الطلب، أو أعاد خطأ، أو كان غير متاح لفترة قصيرة، فالمزود عادةً ما يعيد محاولة نفس الحدث. قد ترى أيضًا حدثين مختلفين يشيران إلى نفس الفعل الواقعي (مثل حدث فاتورة وحدث دفع يربطهما نفس الدفع). ويمكن أن تصل الأحداث بترتيب غير متوقع أيضًا، خصوصًا مع متابعة سريعة مثل الاستردادات.
إذا لم يكن المعالج لديك قابلًا للتكرار (idempotent)، فقد يطبّق نفس الحدث مرتين، مما يخلق مشاكل يلاحظها العملاء وفرق المالية فورًا:
- وضع الفاتورة كمدفوعة مرتين، مما يخلق قيودًا محاسبية مكررة
- تطبيق التجديد مرتين، مما يمدد الوصول أكثر من اللازم
- منح صلاحيات مرتين (اعتمادات إضافية، مقاعد، أو ميزات)
- الاستردادات أو المرتجعات لا تعكس الوصول بشكل صحيح
هذا ليس مجرد "أفضل ممارسة". إنه الفرق بين فوترة تبدو موثوقة وفوترة تولّد تذاكر دعم.
هدف هذه القائمة بسيط: عامل كل حدث وارد كأنه "يُطبّق مرة واحدة على الأكثر." خزّن معرفًا ثابتًا لكل حدث، تعامل مع إعادة المحاولات بأمان، وحدث الفواتير والاشتراكات والصلاحيات بطريقة مسيطرة. إذا كنت تبني الخلفية في أداة بلا كود مثل AppMaster، فتنطبق نفس القواعد: تحتاج إلى نموذج بيانات واضح وتدفق معالج متكرر يبقى صحيحًا تحت إعادة المحاولات.
أساسيات المعاملية (Idempotency) التي يمكنك تطبيقها على webhooks
المعاملية تعني أن معالجة نفس المدخل أكثر من مرة تُنتج نفس الحالة النهائية. بمصطلحات الفوترة: تبقى الفاتورة مدفوعة مرة واحدة، يتم تحديث الاشتراك مرة واحدة، ويُمنح الوصول مرة واحدة، حتى لو تم تسليم الويب هوكس مرتين.
يعيد المزودون المحاولات عندما ينتهي وقت استجابة نقطة النهاية لديك، أو تُعيد خطأ 5xx، أو يهبط الشبكة. تلك المحاولات تكرر نفس الحدث. هذا يختلف عن حدث منفصل يمثل تغييرًا حقيقيًا، مثل استرداد بعد أيام. الأحداث الجديدة لها معرفات مختلفة.
لجعل هذا يعمل، تحتاج إلى أمرين: معرفات ثابتة و"ذاكرة" صغيرة لما سبق أن رأيته.
ما المعرفات المهمة (وماذا تخزن)
تضم معظم منصات الدفع معرف حدث فريد خاص بحدث الويب هوكس. بعضها يتضمن أيضًا معرف الطلب، مفتاح idempotency، أو معرف كائن الدفع الفريد (مثل charge أو payment intent) داخل الحمولة.
خزن ما يساعدك على الإجابة عن سؤال واحد: "هل طبقت هذا الحدث بالضبط من قبل؟"
حد أدنى عملي:
- معرف الحدث (المفتاح الفريد)
- نوع الحدث (مفيد للتصحيح)
- طابع الاستلام الزمني
- حالة المعالجة (processed/failed)
- إشارة إلى العميل، الفاتورة، أو الاشتراك المتأثر
الخطوة الأساسية هي تخزين معرف الحدث في جدول بقيد فريد. بعدها يمكن لمعالجك أن يفعل هذا بأمان: إدراج معرف الحدث أولًا؛ إذا كان موجودًا بالفعل، توقف وارجع 200.
إلى متى تحتفظ بسجلات إزالة التكرار
احتفظ بسجلات إزالة التكرار فترة كافية لتغطية إعادة المحاولات المتأخرة والتحقيقات. نافذة شائعة هي 30 إلى 90 يومًا. إذا كنت تتعامل مع نزاعات أو دورات اشتراك أطول، احتفظ بها لفترة أطول (6 إلى 12 شهرًا)، وامسح الصفوف القديمة حتى يبقى الجدول سريعًا.
في خلفية مولدة مثل AppMaster، هذا يترجم بوضوح إلى نموذج بسيط WebhookEvents مع حقل فريد على معرف الحدث، بالإضافة إلى عملية عمل (Business Process) تخرج مبكرًا عند اكتشاف تكرار.
صمم نموذج بيانات بسيط لإزالة تكرار الأحداث
معالج webhooks الجيد هو في الغالب مشكلة بيانات. إذا استطعت تسجيل كل حدث مزود مرة واحدة بالضبط، يصبح كل ما يلي أكثر أمانًا.
ابدأ بجدول واحد يعمل كسجل إيصال. في PostgreSQL (بما في ذلك عند نمذجته في AppMaster’s Data Designer)، اجعله صغيرًا وصارمًا حتى تفشل التكرارات بسرعة.
الحد الأدنى الذي تحتاجه
فيما يلي أساس عملي لجدول webhook_events:
provider(نص، مثل "stripe")provider_event_id(نص، مطلوب)status(نص، مثل "received", "processed", "failed")processed_at(timestamp، قابل لأن يكون فارغًا)raw_payload(jsonb أو نص)
أضف قيدًا فريدًا على (provider, provider_event_id). تلك القاعدة الوحيدة هي الحاجز الرئيسي لإزالة التكرار.
ستحتاج أيضًا إلى معرفات العمل التي تستخدمها للعثور على السجلات لتحديثها. هذه مختلفة عن معرف حدث الويب هوكس.
أمثلة شائعة تتضمن customer_id, invoice_id, و subscription_id. احتفظ بها كنص لأن المزودين غالبًا ما يستخدمون معرفات غير رقمية.
الحمولة الخام مقابل الحقول المحللة
خزن الحمولة الخام حتى تتمكن من التصحيح وإعادة المعالجة لاحقًا. الحقول المحللة تُسهل الاستعلامات والتقارير، لكن خزّن فقط ما تستخدمه بالفعل.
نهج بسيط:
- دوّم دائمًا
raw_payload - خزّن أيضًا بعض المعرفات المحللة التي تستعلم عنها كثيرًا (customer, invoice, subscription)
- خزّن
event_typeمعرّفًا وموحدًا (نص) للتصفية
إذا وصل حدث invoice.paid مرتين، يمنع القيد الفريد الإدراج الثاني. ما زال لديك الحمولة الخام للتدقيق، والمعرّف المحلل للفاتورة يجعل من السهل العثور على سجل الفاتورة الذي تم تحديثه في المرة الأولى.
خطوة بخطوة: تدفق معالج webhooks آمن
معالج آمن ممل عن قصد. يتصرف بنفس الطريقة في كل مرة، حتى عندما يعيد المزود إرسال نفس الحدث أو يرسل الأحداث بترتيب غير متوقع.
تدفق الخمس خطوات الذي يجب اتباعه في كل مرة
-
تحقق من التوقيع وحلل الحمولة. ارفض الطلبات التي تفشل فحوصات التوقيع، أو لها نوع حدث غير متوقع، أو لا يمكن تحليلها.
-
اكتب سجل الحدث قبل أن تلمس بيانات الفوترة. احفظ معرف حدث المزود، النوع، وقت الإنشاء، والحمولة الخام (أو هاش). إذا كان معرف الحدث موجودًا بالفعل، اعتبره تكرارًا وتوقف.
-
اربط الحدث بسجل "المالك" الواحد. قرر ما الذي ستحدّثه: الفاتورة، الاشتراك، أو العميل. خزّن المعرفات الخارجية على سجلاتك حتى تتمكن من البحث عنها مباشرة.
-
طبق تغيير حالة آمن. حرك الحالة إلى الأمام فقط. لا تتراجع عن فاتورة مدفوعة لأن حدث "invoice.updated" متأخر وصل. سجّل ما طبقتَه (الحالة القديمة، الحالة الجديدة، الطابع الزمني، معرف الحدث) للمراجعة.
-
أجب بسرعة وسجّل النتيجة. أعد النجاح بمجرد أن يُخزّن الحدث بأمان وأنه تمت معالجته أو تجاهله. سجل ما إذا تمت معالجته، أو تم تجاهله كنسخة مكررة، أو تم رفضه، ولماذا.
في AppMaster، عادةً ما يصبح هذا جدول قاعدة بيانات لأحداث الويب هوكس بالإضافة إلى Business Process يتحقق من "هل رأينا معرف الحدث؟" ثم يشغّل خطوات التحديث الأدنى.
التعامل مع إعادة المحاولات، انتهاء المهلات، والتسليم غير المتسلسل
يعيد المزودون webhooks عندما لا يحصلون على رد نجاح سريع. قد يرسلون الأحداث بترتيب غير متسلسل أيضًا. يحتاج معالجك لأن يبقى آمنًا عندما يصل نفس التحديث مرتين، أو يصل تحديث لاحق أولًا.
قاعدة عملية واحدة: رد سريعًا، وانجز العمل لاحقًا. عامل طلب الويب هوكس كإيصال، وليس مكانًا لتنفيذ منطق ثقيل. إذا استدعيت واجهات برمجة خارجية، أو ولّدت ملفات PDF، أو أعدت حسابات داخل الطلب، فأنت تزيد من انتهاء المهلات وتستدعي مزيدًا من المحاولات.
التسليم غير المتسلسل: احتفظ بأحدث حقيقة
التسليم غير المتسلسل أمر طبيعي. قبل تطبيق أي تغيير، استخدم فحصين:
- قارن الطوابع الزمنية: طبّق الحدث فقط إذا كان أحدث مما خزّنته بالفعل لذلك الكائن (الفاتورة، الاشتراك، الصلاحية).
- استخدم أولوية الحالة عندما تكون الطوابع الزمنية قريبة أو غير واضحة: المدفوع beats المفتوح، الملغى beats النشط، المسترد beats المدفوع.
إذا سجّلت بالفعل فاتورة كمدفوعة ووصل حدث "open" متأخر، تجاهله. إذا تلقيت "canceled" ولاحقًا تحديث "active" قديم، احتفظ بالحالة الملغاة.
تجاهل أم انتظار
تجاهل الحدث عندما تستطيع إثبات أنه قديم أو مُطبق بالفعل (نفس معرف الحدث، طابع زمني أقدم، أولوية حالة أقل). ضع الحدث في طابور عندما يعتمد على بيانات غير موجودة بعد، مثل تحديث اشتراك يصل قبل وجود سجل العميل.
نمط عملي:
- خزّن الحدث فورًا بحالة معالجة (received, processing, done, failed)
- إذا كانت التبعيات مفقودة، علّمه بوضع الانتظار وأعد المحاولة في الخلفية
- ضع حدًا لعدد المحاولات ونبه بعد فشل متكرر
في AppMaster، هذا مناسب لجدول أحداث الويب هوكس بالإضافة إلى Business Process يقر بالطلب بسرعة ويعالج الأحداث المعلقة بشكل غير متزامن.
تحديث الفواتير والاشتراكات والصلاحيات بأمان
بعد أن تعاملت مع إزالة التكرار، الخطر التالي هو حالة فواتير متفرقة: الفاتورة تقول مدفوعة، لكن الاشتراك ما زال متأخرًا، أو مُنحت صلاحيات مرتين ولم تُلغى. عامل كل webhook كتحول حالة وطبّقه في تحديث ذري واحد.
الفواتير: اجعل تغييرات الحالة أحادية التوجيه
يمكن أن تنتقل الفواتير عبر حالات مثل مدفوعة، مُلغاة، ومُستردة. قد ترى أيضًا دفعات جزئية. لا "تبدّل" حالة الفاتورة اعتمادًا على آخر حدث وصل. خزّن الحالة الحالية بالإضافة إلى المجاميع الرئيسية (amount_paid, amount_refunded) واسمح فقط بالانتقالات الأمامية الآمنة.
قواعد عملية:
- وسم الفاتورة كمدفوعة مرة واحدة فقط، في المرة الأولى التي ترى فيها حدث الدفع.
- بالنسبة للاستردادات، زد
amount_refundedحتى إجمالي الفاتورة؛ لا تُنقصه. - إذا كانت الفاتورة ملغاة، أوقف إجراءات التنفيذ، لكن احتفظ بالسجل للمراجعة.
- للدفعات الجزئية، حدّث المبالغ دون منح مزايا "مدفوعة تمامًا".
الاشتراكات والصلاحيات: منح مرة، إلغاء مرة
الاشتراكات تتضمن تجديدات، إلغاءات وفترات سماح. احتفظ بحالة الاشتراك وحدود الفترة (current_period_start/end)، ثم استخلص نوافذ الصلاحية من تلك البيانات. يجب أن تكون الصلاحيات سجلات صريحة، لا قيمة منطقية واحدة فقط.
للسيطرة على الوصول:
- منح صلاحية واحدة لكل مستخدم لكل منتج لكل فترة
- سجل إلغاء واحد عند انتهاء الوصول (إلغاء، استرداد، مرتجعات)
- سِجل تدقيق يبيّن أي حدث webhooks تسبب في كل تغيير
استخدم معاملة واحدة لتجنب الحالات المتفرقة
طبق تحديثات الفاتورة والاشتراك والصلاحيات في معاملة قاعدة بيانات واحدة. اقرَأ الصفوف الحالية، تحقق مما إذا كان قد طُبّق هذا الحدث بالفعل، ثم اكتب كل التغييرات معًا. إذا فشل شيء، عدّل كل شيء حتى لا ينتهي بك الحال بـ "فاتورة مدفوعة" ولكن "لا وصول"، أو العكس.
في AppMaster، هذا غالبًا ما يطابق Business Process واحد يحدث PostgreSQL في مسار مراقب واحد ويكتب مدخل تدقيق جنبًا إلى جنب مع التغيير التجاري.
فحوصات الأمان وسلامة البيانات لنقاط نهاية webhooks
أمن الويب هوكس جزء من الصحة. إذا استطاع مهاجم الوصول إلى نقطة النهاية، يمكنه محاولة إنشاء حالات "مدفوعة" مزيفة. حتى مع إزالة التكرار، تحتاج إلى إثبات أن الحدث حقيقي وحماية بيانات العملاء.
تحقق من المرسل قبل أن تمس بيانات الفوترة
تحقق من التوقيع على كل طلب. بالنسبة لـ Stripe، عادةً ما يعني ذلك فحص ترويسة Stripe-Signature، باستخدام جسم الطلب الخام (لا تُعدّل JSON)، ورفض الأحداث ذات الطابع الزمني القديم. عامل غياب الترويسات كفشل حاسم.
تحقّق من الأساسيات مبكرًا: طريقة HTTP صحيحة، Content-Type، وحقول مطلوبة (معرف الحدث، النوع، ومعرف الكائن الذي ستستخدمه للعثور على الفاتورة أو الاشتراك). إذا بنيت هذا في AppMaster، احتفظ بسر التوقيع في متغيرات البيئة أو إعداد آمن، لا في قاعدة البيانات أو كود العميل.
قائمة فحص سريعة للأمان:
- ارفض الطلبات بلا توقيع صالح وطابع زمني طازج
- اطلُب الترويسات ونوع المحتوى المتوقع
- استخدم وصول قاعدة بيانات بأقل امتيازات لمعالج الويب هوكس
- خزّن الأسرار خارج الجداول (env/config)، دوّرها عند الحاجة
- أعد 2xx فقط بعد أن تخزن الحدث بأمان
اجعل السجلات مفيدة دون تسريب أسرار
سجل ما يكفي للتصحيح وإثبات النزاعات، لكن تجنّب القيم الحساسة. خزّن مجموعة آمنة من PII: معرف عميل المزود، معرف المستخدم الداخلي، وربما بريد إلكتروني مقنّن (مثل a***@domain.com). لا تخزن بيانات البطاقة كاملة، أو العناوين الكاملة، أو رؤوس التفويض الخام.
سجل ما يساعدك على إعادة بناء ما حدث:
- معرف حدث المزود، النوع، وقت الإنشاء
- نتيجة التحقق (signature ok/failed) دون تخزين التوقيع
- قرار إزالة التكرار (جديد مقابل مُعالج بالفعل)
- معرفات السجلات الداخلية التي تم لمسها (invoice/subscription/entitlement)
- سبب الخطأ وعدد المحاولات (إن وضعت طابورًا للمحاولات)
أضف حماية أساسية من الإساءة: حد السرعة حسب IP وحسب معرف العميل عندما يكون ممكنًا، وفكر في السماح فقط بنطاقات IP المعروفة للمزود إذا كان إعدادك يدعم ذلك.
أخطاء شائعة تسبب خصومات مزدوجة أو منح وصول مزدوج
معظم أخطاء الفوترة ليست عن الحساب. تحدث عندما تعامل تسليم webhooks كرسالة موثوقة واحدة.
أخطاء تؤدي غالبًا إلى تحديثات مكررة:
- إزالة التكرار بالاستناد إلى الطابع الزمني أو المبلغ بدلًا من معرف الحدث. قد تتشارك أحداث مختلفة نفس المبلغ، وإعادة المحاولات قد تصل بعد دقائق. استخدم معرف الحدث الفريد للمزود.
- تحديث قاعدة البيانات قبل التحقق من التوقيع. تحقّق أولًا، ثم حلل، ثم اتخذ الإجراء.
- التعامل مع كل حدث كمصدر للحقيقة دون فحص الحالة الحالية. لا تضع علامة الفاتورة كمدفوعة إن كانت بالفعل مدفوعة أو مستردة أو ملغاة.
- إنشاء صلاحيات متعددة لنفس عملية الشراء. يمكن أن تُنشئ إعادة المحاولات صفوفًا مكررة. فضّل upsert مثل "تأكد من وجود صلاحية للـ subscription_id" ثم حدث التواريخ/القيود.
- فشل الويب هوكس لأن خدمة إشعارات خارجية متوقفة. البريد الإلكتروني، الرسائل، Slack، أو Telegram لا ينبغي أن تعيق الفوترة. ضع الإشعارات في طابور وارجع نجاحًا بعد تخزين تغييرات الفوترة الأساسية بأمان.
مثال بسيط: يصل حدث تجديد مرتين. التسليم الأول ينشئ صف صلاحية. إعادة المحاولة تنشئ صفًا ثانيًا، ويرى تطبيقك "صلاحيتان نشطتان" ويمنح مقاعد أو اعتمادات إضافية.
في AppMaster، الحل غالبًا يتعلق بالتدفق: تحقق أولًا، أدخل سجل الحدث مع قيد فريد، طبق تحديثات الفوترة مع فحوصات الحالة، وأرسل الآثار الجانبية (إيميلات، إيصالات) إلى خطوات غير متزامنة حتى لا تولد عاصفة إعادة محاولات.
مثال واقعي: تجديد مكرر ثم استرداد لاحق
النمط مخيف لكنه يمكن التحكم فيه إذا كان المعالج آمنًا لإعادة التشغيل.
العميل على خطة شهرية. Stripe يرسل حدث تجديد (مثل invoice.paid). خادمك يستلمه، يحدث قاعدة البيانات، لكنه يستغرق وقتًا طويلًا للرد 200 (برد بارد، قاعدة بيانات مشغولة). تفترض Stripe أنه فشل وتعيد محاولة نفس الحدث.
في التسليم الأول، تمنح الوصول. في إعادة المحاولة، تكتشف أنه نفس الحدث ولا تفعل شيئًا. لاحقًا يصل حدث استرداد (مثل charge.refunded) وتلغي الوصول مرة واحدة.
طريقة بسيطة لنمذجة الحالة في قاعدة البيانات (جداول يمكنك بناؤها في AppMaster Data Designer):
webhook_events(event_id UNIQUE, type, processed_at, status)invoices(invoice_id UNIQUE, subscription_id, status, paid_at, refunded_at)entitlements(customer_id, product, active, valid_until, source_invoice_id)
كيف ينبغي أن تبدو قاعدة البيانات بعد كل حدث
بعد الحدث A (تجديد، التسليم الأول): تُضاف صف جديد إلى webhook_events لـ event_id=evt_123 مع status=processed. تُعلَن invoices كمدفوعة. entitlements.active=true وvalid_until يتحرك إلى الأمام لمدة دورة الفوترة.
بعد الحدث A مرة أخرى (إعادة المحاولة): يفشل الإدراج في webhook_events (قيد event_id فريد) أو يرى المعالج أنه مُعالج بالفعل. لا تغيّر في الفواتير أو الصلاحيات.
بعد الحدث B (استرداد): صف جديد في webhook_events لـ event_id=evt_456. يُعيّن invoices.refunded_at وتصبح status=refunded. تُعيّن entitlements.active=false (أو يُضبط valid_until إلى الآن) باستخدام source_invoice_id لإلغاء الوصول مرة واحدة.
التفصيل المهم هو التوقيت: فحص إزالة التكرار يحدث قبل أي كتابة للمنح أو الإلغاء.
قائمة التحقق السريعة قبل الإطلاق
قبل تفعيل webhooks الحية، تريد دليلًا يُثبت أن حدثًا واحدًا من العالم الحقيقي يحدث تحديث سجلات الفوترة مرة واحدة فقط، حتى لو أرسله المزود مرتين (أو عشر مرات).
استخدم هذه القائمة للتحقق من الإعداد نهاية إلى نهاية:
- أكد أن كل حدث وارد يُخزّن أولًا (الحمولة الخام، معرف الحدث، النوع، وقت الإنشاء، ونتيجة التحقق من التوقيع)، حتى لو فشلت الخطوات اللاحقة.
- تحقق من اكتشاف التكرارات مبكرًا (نفس معرف حدث المزود) وأن المعالج يخرج دون تغيير الفواتير أو الاشتراكات أو الصلاحيات.
- أثبت أن التحديث التجاري يحدث مرة واحدة فقط: تغيير حالة فاتورة واحد، تغيير حالة اشتراك واحد، منح أو إلغاء صلاحية واحد.
- تأكد من تسجيل الأخطاء بتفاصيل كافية لإعادة التشغيل بأمان (رسالة الخطأ، الخطوة التي فشلت، حالة المحاولة).
- اختبر أن المعالج يعيد استجابة بسرعة: أقر بالاستلام بمجرد التخزين، وتجنب الأعمال البطيئة داخل الطلب.
لا تحتاج إلى إعداد مراقبة كبير لتبدأ، لكن تحتاج إشارات. تابع هذه الأشياء من السجلات أو لوحات بسيطة:
- ارتفاع مفاجئ في التسليمات المكررة (طبيعي غالبًا، لكن القفزات الكبيرة قد تشير إلى انتهاء مهلات أو مشاكل المزود)
- معدل خطأ مرتفع حسب نوع الحدث (مثل فشل دفع الفاتورة)
- تراكم متزايد من الأحداث العالقة في المحاولات
- فحوصات التناقض (فاتورة مدفوعة لكن صلاحية مفقودة، اشتراك ملغى لكن الوصول ما زال نشطًا)
- زيادة مفاجئة في زمن المعالجة
إذا بنيت هذا في AppMaster، احتفظ بتخزين الأحداث في جدول مخصص في Data Designer واجعل "وسم كمُعالج" قرارًا ذريًا واحدًا في Business Process الخاص بك.
الخطوات التالية: اختبر، راقب، وابنِه في خلفية بلا كود
الاختبار هو حيث تثبت المعاملية نفسها. لا تجرِ المسار السليم فقط. أعد تشغيل نفس الحدث عدة مرات، أرسل الأحداث بترتيب غير متوقع، وأجبَر انتهاء مهلات حتى يعيد المزود المحاولة. التسليم الثاني والثالث والعاشر يجب ألا يغيّر شيئًا.
خطط لإعادة المعالجة مبكرًا. عاجلًا أم آجلًا سترغب في إعادة معالجة أحداث سابقة بعد إصلاح خطأ، تغيير مخطط، أو حادث مزود. إذا كان المعالج حقًا قابلًا للتكرار، تصبح إعادة المعالجة "إعادة تشغيل الأحداث عبر نفس خط الأنابيب" دون إنشاء مكررات.
كما يحتاج فريق الدعم إلى دليل عملي صغير حتى لا تتحول المشكلات إلى تخمين:
- اعثر على معرف الحدث وتحقق مما إذا كان مسجلاً كمُعالَج.
- افحص سجل الفاتورة أو الاشتراك وتحقق من الحالة والطوابع الزمنية المتوقعة.
- راجع سجل الصلاحية (ما الوصول الذي مُنح، متى، ولماذا).
- إذا لزم الأمر، أعد تشغيل المعالجة لذلك المعرف حدث واحد في وضع إعادة معالجة آمن.
- إذا كانت البيانات غير متسقة، طبق إجراءً تصحيحيًا واحدًا وسجّله.
إذا أردت تنفيذ هذا بدون كتابة كثير من البنية التحتية، AppMaster (appmaster.io) يتيح لك نمذجة الجداول الأساسية وبناء تدفق webhooks في Business Process مرئي، مع توليد شيفرة مصدر حقيقية للخلفية.
جرّب بناء معالج webhooks نهاية إلى نهاية في خلفية مولدة بلا كود وتأكد من بقائه آمنًا تحت إعادة المحاولات قبل توسيع الحركة والإيرادات.
الأسئلة الشائعة
تكرار تسليمات الويب هوكس أمر طبيعي لأن مقدمي الخدمة يضمنون التوصيل مرة على الأقل. إذا انتهت مهلة نقطة النهاية لديك، أو أعادت الخادم 5xx، أو انقطعت الاتّصال مؤقتًا، فالمزوّد سيعاود إرسال نفس الحدث حتى يحصل على استجابة ناجحة.
استخدم معرف الحدث الفريد الذي يقدمه المزود (معرف الحدث للويب هوكس)، وليس المبلغ أو الطابع الزمني أو بريد العميل. خزّن هذا المعرف مع قيد فريد حتى تُكتشف إعادة المحاولة فورًا وتُتجاهل بأمان.
أدرج سجل الحدث أولًا، قبل تحديث الفواتير أو الاشتراكات أو الصلاحيات. إذا فشل الإدراج لأن معرف الحدث موجود بالفعل، أوقف المعالجة وارجع نجاحًا بحيث لا تُنشأ تحديثات مزدوجة عند إعادة المحاولات.
احتفظ بها لفترة تغطي إعادة المحاولات المتأخرة ولأغراض التحقيق. الافتراضي العملي هو 30–90 يومًا، ولفترات أطول (مثل 6–12 شهرًا) إن كنت تتعامل مع نزاعات أو استردادات أو دورات اشتراك طويلة، ثم قم بحذف الصفوف القديمة للحفاظ على سرعة الاستعلامات.
تحقق من التوقيع قبل المساس ببيانات الفوترة، ثم حلل الحقول المطلوبة. إذا فشل التحقق من التوقيع، ارفض الطلب ولا تُجري تغييرات فواتير، لأن إزالة التكرار لا تحميك من أحداث "مدفوعة" مزيفة.
فضلًا اعترف بالاستلام سريعًا بعد أن تُخزن الحدث بأمان، وانقل الأعمال الأثقل إلى المعالجة الخلفية. المعالجات البطيئة تزيد من انتهاء المهلات، ما يسبب مزيدًا من المحاولات التي ترفع احتمال التكرار إذا لم تكن كل الأشياء معاملة بلا أثر جانبي.
طبق فقط تغييرات تنقل الحالة إلى الأمام وتجاهل الأحداث القديمة. استخدم طوابع زمنية للأحداث عندما تتوفر، وأولوية حالات بسيطة (مثل: refunded لا يُستبدَل بـ paid، و canceled لا يُستبدَل بـ active).
لا تُنشئ صف صلاحية جديد على كل حدث. استخدم قاعدة شبيهة بالـ upsert مثل «تأكد من وجود صلاحية واحدة لكل مستخدم/منتج/فترة (أو لكل اشتراك)»، ثم حدث التواريخ/الحدود، وسجل معرف الحدث الذي تسبب في التغيير للمراجعة.
اكتب تغييرات الفاتورة والاشتراك والصلاحيات داخل معاملة قاعدة بيانات واحدة حتى تنجح أو تفشل معًا. هذا يمنع حالات متفرقة مثل "فاتورة مدفوعة" بدون "منح وصول"، أو العكس.
نعم. أنشئ نموذجًا WebhookEvents مع معرف حدث فريد، ثم ابنِ Business Process يتحقق من «هل رأينا هذا المعرف؟» ويخرج مبكرًا إن كان كذلك. نمذج الفواتير/الاشتراكات/الصلاحيات في Data Designer يحمي من إنشاء صفوف مكررة عند إعادة المحاولات أو إعادة التشغيل.


