خطة اختبار ما قبل الإنتاج لواجهة برمجة تطبيقات المحاسبة (Accounting API)
دليل عملي للموثوقية موجّه لفرق الهندسة: معالجة الكتابات المزدوجة، إعادة استخدام مفاتيح عدم التكرار (idempotency)، تواقيع إخطارات الويب، الأحداث غير المرتبة زمنياً، المبالغ العشرية الدقيقة، النطاقات (scopes)، إقفالات الفترات، وآليات الاسترداد.
الحصول على استجابة من نوع 201 Created من واجهة برمجة تطبيقات المحاسبة لا يعطيك أي تأكيد تقريباً؛ فهو يؤكد فقط أن الخادم قد أجاب، ولكنه لا يضمن أن فاتورة واحدة فقط موجودة، أو أن المدين يساوي الدائن، أو أنه تم تخصيص رقم المستند مرة واحدة فقط، أو أن إعادة المحاولة بعد انقطاع الاتصال لن تؤدي إلى تسجيل نسخة ثانية. تأتي معظم حالات التكرار الإنتاجي في المحاسبة من هذه الثغرة: عملية تعديل تمّ تنفيذها على الخادم بينما بقي العميل جاهلاً بالنتيجة فأعاد المحاولة بهدوء مستخدماً مفتاحاً جديداً.
هذه الخطة مخصصة للفرق التي تقيم واجهة برمجة تطبيقات محاسبية قبل ربطها بالدفاتر الحقيقية، وهي تركز على سلوكيات التعامل مع حالات الفشل لا على المسارات المثالية. يوضح كل قسم أدناه ما يجب اختباره، وما يجب التحقق منه، وما يُعدّ ناجحاً. سياق التنفيذ هنا يتعلق بـ Nordlet، حيث تستخدم واجهة برمجة التطبيقات مفاتيح مصادقة حاملة مقيدة النطاق (scoped bearer keys)، ومبالغ على هيئة سلاسل نصية عشرية (decimal-string amounts)، ومفاتيح عدم تكرار (idempotency keys)، وإخطارات ويب موقعة. لمعرفة البنية الدقيقة لنقاط النهاية وعقود الاستجابة، اقرأ صفحات [اصطلاحات واجهة برمجة التطبيقات (/en/docs/guides/api-conventions/) و[البدء السريع] (/en/docs/guides/getting-started/) بدلاً من الاعتماد على الافتراضات.
المعنى الحقيقي "للنجاح"
لا يثبت أي اختبار أن عملية التكامل المحاسبي آمنة إلا إذا تحقق من الدلالات (semantics) وليس مجرد رموز الحالة (status codes). لكل سيناريو، يجب أن تتأكد مجموعة الاختبارات من الآتي:
- الأثر التجاري: وجود عميل، أو فاتورة، أو قيد دفتر يومية، أو تخصيص رقم، أو انتقال حالة دفع واحد فقط لا غير.
- السلامة المحاسبية: تساوي المدين مع الدائن، وبقاء الدقة النقدية سليمة أثناء عملية التسلسل (serialization).
- سلوك إعادة التشغيل (Replay): إعادة المحاولة تعيد النتيجة الأصلية بدلاً من إنشاء سجل جديد.
- المتانة: وجود سجلات التدقيق وأحداث إخطارات الويب بمجرد اعتماد العملية.
- أخطاء بلا آثار جانبية: الطلبات المرفوضة لا تستهلك أرقام مستندات ولا تكتب أي أسطر دفترية جزئية.
- الاسترداد: إمكانية إعادة المحاولة عند حدوث خطأ عابر دون تكرار أو فقدان دائم للبيانات.
ترسم إرشادات واواجهة برمجة التطبيقات الخاصة بغوغل الحدود بوضوح: العمليات التي ينتج عن تنفيذها المتكرر نفس الحالة النهائية وحدها هي الآمنة لإعادة المحاولة، ويجب أن تحدد واجهة برمجة التطبيقات العمليات التي تتسم بعدم التكرار بدلاً من إعادة المحاولة العشوائية لكل فشل.
إعداد بيئة معزولة وقابلة للمراقبة
استخدم شركة تجريبية في بيئة تجريبية (sandbox)، وليس دفاتر الإنتاج الفعلية. تستخدم الشركة التجريبية في Nordlet نفس الوحدات وسلوكيات واجهة برمجة التطبيقات الخاصة بالشركة الحقيقية، ويتم تعليمها بوضوح كبيانات اختبار، مما يجعلها آمنة لاختبارات التكرار والفشل ذات الحجم الكبير. هذا الوسم غير قابل للتغيير بعد الإنشاء، لذا لا يمكن إعادة تصنيف الدفاتر الحقيقية كبيانات اختبار لاحقاً. لاحظ أن استخدام البيئة التجريبية يخضع للقياس والفوترة تماماً مثل الاستخدام في الشركة الحقيقية، لذا قم بتقدير حجم اختباراتك بما يتوافق مع خطة الأسعار الخاصة بك.
قبل كتابة أي اختبار، قم بتحضير ما يلي:
- شركة تجريبية مخصصة تحمل علامة
isSandbox: true. - مفتاح API للاختبار مقيد النطاق للوحدات قيد الاختبار فقط.
- نقطة نهاية لإخطارات الويب (webhook endpoint) أو نفق محلي يحتفظ بطلب البيانات الخام (raw request body).
- عملاء وموردون أولياء، ومخطط حسابات معروف (chart of accounts).
- فترتان محاسبيتان على الأقل: واحدة مفتوحة والأخرى مقفلة.
- ساعة اختبار أو أداة تاريخ ثابتة (date fixture) إذا كان النظام يدعم ذلك.
- مخزن محلي يسجل كل محاولة طلب، ومفتاح عدم تكرار، وتجزئة الاستجابة (response hash)، وتسليم إخطارات الويب، ونتيجة المطابقة.
لا تقم بتجري اختبارات التكرار على بيانات مرحلية مشتركة (staging data)، فوجود عميل أو فاتورة شاردة من تشغيل سابق يجعل التأكيدات اللاحقة غامضة.
يجب أن تلتقط أداة الاختبار الخاصة بك لكل عملية تعديل: الطريقة، ونقطة النهاية، والنص الكامل للطلب، ومفتاح عدم التكرار، ونطاق المفتاح، ومعرف الارتباط الخاص بالعميل (client correlation ID)، والطوابع الزمنية للبدء والانتهاء، وحالة الاستجابة، والرؤوس (headers)، والنص، ومعرف الطلب، وما إذا كان الاتصال قد انقطع قبل وصول الاستجابة. استخدم سلاسل نصية عشرية ثابتة مثل "75.0000" للقيم المالية. تُمثّل Nordlet القيم المالية كسلاسل عشرية تصل إلى أربعة منازل عشرية، وتستخدم فاتورتها النموذجية هذا الشكل.
الجانب الآخر للإعداد هو حقن الأخطاء (failure injection). يجب أن تكون أداة الاختبار قادرة على تأخير الاستجابة، وقطع اتصال TCP بعد استلام الخادم للطلب، وإرجاع استجابات اصطناعية مثل 429 أو 500 أو 502 أو 503 أو 504، وإرجاع استجابة غير 2xx من مستقبل إخطارات الويب، وتوصيل نفس إخطار الويب مرتين، وإعادة ترتيب الأحداث، وإفساد بايت واحد من نص إخطار الويب، وتغيير حمولة مفتاح عدم التكرار مع الاحتفاظ بالمفتاح، وتشغيل طلبين متطابقين في نفس الوقت، وإقفال فترة بين مرحلة الإعداد ومرحلة الترحيل (posting). هذه السيناريوهات تساوى أكثر من مائة مثال للمسارات المثالية.
تثبيت العقد (contract) قبل كتابة منطق إعادة المحاولة
قم بتوليد أو جلب مخطط OpenAPI وقارنه بعميلك. تنشر Nordlet مخطط OpenAPI الخاص بها في مرجع واجهة برمجة التطبيقات وتُنشئ حزم تطوير البرامج (SDKs) المكتوبة من نفس المخطط، لذا فإن الاختبارات المستندة إلى المخطط تتفوق على التخمينات اليدوية.
تحقق من الحقول والأنواع المطلوبة، والحقول ذات السلاسل العشرية، وتنسيقات التاريخ والطوابع الزمنية، والإجراءات والنطاقات المسموح بها، وشكل غلاف الأخطاء، ومخططات أحداث إخطارات الويب، وتحديد عمليات التعديل التي تقبل مفتاح عدم التكرار، وأي حقول استجابة تحدد الكائن المُنشأ.
معايير النجاح: يرفض العميل الحمولات غير الصالحة محلياً عندما يسمح المخطط بذلك. تتطابق استجابات الخادم مع المخطط المُوثّق. تؤدي القيم العشرية غير الصالحة، والتواريخ الخاطئة، والحقول المطلوبة المفقودة إلى ظهور أخطاء تحقق منظمة. لا تتم محاولة إعادة التشغيل في حال الفشل الحتمي للتحقق من الصحة.
وضع الفشل الواجب اكتشافه: يقوم العميل بتحليل السلسلة "121.0000" إلى رقم عشري ذي دقة ثنائية (binary float) ثم يقوم لاحقاً بتسلسل مبلغ مختلف قليلاً. الأرقام الصحيحة تمر، بينما تفشل أسطر ضريبة القيمة المضافة والكميات الكسرية. اختبر القيم المالية كسلاسل نصية من البداية إلى النهاية.
المصادقة وعزل المستأجرين (Tenant Isolation)
استخدم مفاتيح منفصلة للقراءة والكتابة. ثم اختبر الشبكة بالكامل: مفتاح مفقود، مفتاح غير صالح، مفتاح صالح بنطاق وحدة غير كافٍ، مفتاح صالح بالنطاق الصحيح، مفتاح يخص شركة أخرى، ومحاولة قراءة كائن ينتمي إلى شركة أخرى.
التأكيدات:
- بيانات الاعتماد المفقودة أو غير الصالحة تُرجع
401. - المفتاح الصالح الذي لا يملك الصلاحية المطلوبة يُرجع
403. - لا يتم إنشاء أي أثر محاسبي لأي من حالتي الفشل.
- لا يمكن للطلب الناجح قراءة أو تعديل سجلات شركة أخرى.
- لا تتم أبداً إعادة محاولة فشل الأمان تلقائياً.
معيار النجاح: يمكنك إثبات صحة المصادقة وعزل المستأجرين من خلال عمليات القراءة التي تعقب الاختبار، وليس فقط بالاعتماد على رموز الحالة.
إثبات معاملة نظيفة واحدة
قم بتشغيل مسار صغير وحتمي: أنشئ أو ابحث عن عميل اختبار، أنشئ فاتورة بمبالغ ذات سلاسل عشرية، أصدرها، اقرأ الف فاتورة وتأثيرها المحاسبي، اقرأ سجل التدقيق، واستلم إخطار الويب. يوضح مثال البدء السريع لـ Nordlet أن إصدار الفاتورة يخصص رقماً متسلسلاً بلا فجوات، ويتحقق من أن الفترة مفتوحة، ويُرحّل قيد دفتر يومية متوازن في نفس المعاملة.
تأكد من أن الفاتورة تصل إلى الحالة المتوقعة، ويتم تخصيص رقم المستند مرة واحدة بالضبط، ويتساوى المدين مع الدائن، وتتطابق ضريبة القيمة المضافة وإجماليات السطور مع حساب التقريب لأقرب قيمة (half-up)، ويذكر سجل التدقيق الجهة الفاعلة والتغيير، ويتم تسليم إخطار الويب في النهاية، وتتفق استجابة واجهة برمجة التطبيقات وعملية القراءة اللاحقة على معرف الفاتورة وحالتها.
هناك تمييز يستحق الاحتفاظ به: وصول إخطار الويب ليس دليلاً على إتمام عملية التعديل؛ فاستجابة واجهة برمجة التطبيقات بالإضافة إلى قراءة البيانات هما تأكيدات المعاملة الأساسية لديك، بينما يثبت إخطار الويب عملية الإبلاغ للأنظمة اللاحقة ويتم اختباره بشكل منفصل.
عدم تكرار العمليات (Idempotency): نفس المفتاح ونفس الحمولة
أنشئ مفتاحاً واحداً لكل عملية تجارية منطقية، وليس مفتاحاً واحداً لكل محاولة شبكة. أرسل عملية التعديل بالمفتاح K والحمولة B، واحفظ المعرف المُنشأ، ثم أرسل نفس الطلب بالضبط مرة أخرى.
تأكد من أن الاستجابة الثانية تُمثّل نفس العملية، ومعرف الكائن متطابق، وهناك كائن تجاري واحد، وترحيل واحد، ورقم مستند واحد، وتأثير مالي واحد. يجب أن تحمل الاستجابة المعادة رأس الاستجابة الموثق المخصص لإعادة التشغيل وهو x-idempotent-replay: true في حالة Nordlet، ويجب ألا يُظهر مسار التدقيق أي تعديل ثانٍ.
هناك قاعدتا تخزين تغيران ما ينبغي أن تتوقعه حلقة إعادة المحاولة لديك، لذا اختبرهما مباشرة: يتم إعادة إرسال الاستجابة من الفئة 4xx المخزنة تماماً مثل أي استجابة أخرى، بينما لا يتم تخزين استجابة الفئة 5xx على الإطلاق، لذا فإن إعادة المحاولة بعد حدوث خطأ في الخادم تعيد تنفيذ العملية بدلاً من إعادة تشغيل استجابة مخزنة. تنتهي صلاحية المفاتيح أيضاً، ففي Nordlet تنتهي بعد 24 ساعة، مما يحدد النقطة الزمنية التي تتوفر فيها عملية إعادة التشغيل.
تعد وثائق Nordlet بأن إضافة رأس Idempotency-Key يمنع الطلب المعاد محاولته من إنشاء نسخة مكررة، وتُعرّف اصطلاحات واجهة برمجة التطبيقات الخاصة بها رأس إعادة التشغيل الدقيق ومتطلبات مطابقة الاستجابة حرفياً. يتطابق هذا المبدأ مع نموذج Stripe المنشور: المفتاح يحدد العملية المنطقية، والتكرار يعيد النتيجة المخزنة، والمفتاح المُعاد استخدامه بمعلمات مختلفة يتم رفضه بدلاً من تغييره بصمت.
معيار النجاح: انتقال الحالة المالية يحدث مرة واحدة فقط بغض النظر عن عدد مرات إرسال العميل لنفس الطلب داخل نافذة إعادة التشغيل.
عدم تكرار العمليات: نفس المفتاح وحمولة مختلفة
أرسل الطلب الأصلي بالمفتاح K والحمولة B1، ثم أرسل طلباً ثانياً بالمفتاح K والحمولة B2 حيث يختلف مبلغ أو عميل أو تاريخ أو سطر واحد على الأقل.
النتيجة المتوقعة: رُفض الطلب مع خطأ إعادة استخدام المفتاح المُوثّق (تُرجع Nordlet خطأ 422 idempotency_key_reuse)، وبقي السجل الأصلي دون مساس، ولم يظهر أي سجل ثانٍ أو رقم أو تعديل تدقيقي، ولا يحاول العميل "إصلاح" الأمر بتوليد مفتاح جديد. القبول الصامت للحمولة B2 يجعل مفاتيح إعادة المحاولة غير آمنة.
طلبات التكرار المتزامنة
قم بإرسال طلبين متطابقين بنفس المفتاح في نفس اللحظة بالضبط. بناءً على السلوك المُوثّق، يتم تنفيذ أحد الطلبين بينما يتلقى الآخر تعارضاً قيد التنفيذ (تُرجع Nordlet رمز 409 idempotency_in_progress)، أو يلاحظ كلاهما نفس النتيجة في النهاية.
تأكد من أن كلا الاستدعاءين لا يمكنهما إنشاء تأثيرات مالية مستقلة، وأنه يتم تخصيص رقم مستند واحد على الأكثر، وأنه تتم إعادة محاولة التعارض المؤقت بنفس المفتاح وليس بمفتاح جديد، وأن المورد النهائي مكتمل وقابل للقراءة، وأن سجل عدم التكرار لا يبقى عالقاً بشكل دائم.
وضع الفشل: مكتبة إعادة محاولة تُنشئ معرف فريد عالمي (UUID) جديداً لكل محاولة تحول عملية منطقية واحدة إلى عدة عمليات كتابة مستقلة وتُبطل ميزة عدم التكرار تماماً.
النتيجة غير المؤكدة بعد انقطاع الاتصال
هذا هو أهم محاكاة إنتاجية على الإطلاق. أرسل عملية تعديل بالمفتاح K، دع الخادم يعتمدها، واقطع الاتصال قبل وصول الاستجابة، وسجّل النتيجة كحالة غير معروفة، ثم أعد المحاولة بنفس المفتاح K وتأكد من التطابق عبر قراءة المورد وبيانات التدقيق.
تأكد من أن إعادة المحاولة تُرجع استجابة إعادة التشغيل الأصلية أو المُوثّقة، وأن هناك أثراً جانبياً مالياً واحداً فقط، وأن العميل يعلن أن العملية قد اكتملت فقط بعد إعادة تشغيل ناجحة أو قراءة مطابقة، وأنه لم يتم توليد أي مفتاح جديد. مهلة الانتظار (timeout) لا تعني أن "شيئاً لم يحدث". تصف Stripe خاصية عدم التكرار بدقة على أنها حماية ضد أخطاء الاتصال التي ربما يكون الخادم قد عَالَج فيها عملية التعديل قبل أن يتمكن العميل من تلقي الاستجابة.
سياسة إعادة محاولة متحفظة
تعتمد قرارات إعادة المحاولة على كل من الخطأ وما إذا كانت العملية تتسم بعدم التكرار، وليس على طريقة HTTP وحدها.
تُعاد محاولتها عادةً، مع الاحتفاظ بنفس المفتاح: إعادة ضبط الاتصال أو انتهاء المهلة بعد عملية تعديل لا تتكرر، و 408، و 429 بعد احترام رأس retry-after، والاستجابات 502/503/504. يمكن إعادة محاولة استجابة عدم التكرار الموثقة التي تشير إلى أن العملية قيد التنفيذ بعد تأخير قصير.
لا تُعاد محاولتها بدون مطابقة: أخطاء التحقق 400/422، وأخطاء المصادقة 401/403، والخطأ 404 للمورد المفقود، وتعارضات الأعمال 409 غير المرتبطة بمفتاح قيد التنفيذ، والحمولة المتغيرة على مفتاح موجود، ورفض قفل الفترة.
تأكد من تطبيق التراجع الأسي المحدود مع العشوائية (jitter)، والحد الأقصى الصريح للمحاولات ووقت التوقف المنقضي، واحترام رأس retry-after لحدود الاستخدام، والاحتفاظ بنفس المفتاح عبر عمليات إعادة المحاولة لعملية واحدة، ومفتاح جديد لكل عملية جديدة، وسجلات تفصل المحاولة الأصلية عن المحاولات اللاحقة.
اختبر حدود معدل الاستخدام (rate limiting) بمفردها. تجاوز الحد المُوثّق (تسمح Nordlet بـ 300 طلب في الدقيقة لكل مفتاح API افتراضياً، وتحمل بعض نقاط النهاية غير المصادق عليها حدوداً أدنى لكل عنوان)، ثم تأكد من أن الخادم يُرجع استجابة تجاوز الحد، ويقوم العميل بتحليل رأس retry-after كتأخير وليس كخطأ، ويتوقف مؤقتاً بدلاً من إرسال الطلبات بكثافة، وتعيد محاولة التعديل المقيدة استخدام المفتاح الأصلي. تُبلغ رؤوس x-ratelimit-* عن الرصيد المتبقي، مما يشكل نقطة تحقق مسبقة جيدة. ابقِ اختبارات حدود المعدل بعيدة عن التأكيدات المالية ما لم تتمكن أداة الاختبار الخاصة بك من التمييز بين المحاولة المقيدة والمحاولة المُعتمدة.
التحقق من توقيع إخطارات الويب
ابني مستقبل إخطارات ويب يحتفظ بالبايتات الخام. لكل حدث: التقط النص الخام، واقرأ رأس x-nordlet-signature، واحسب توقيع HMAC-SHA256 المتوقع باستخدام سر الاشتراك، وقارن باستخدام دالة مقاومة للتوقيت الثابت (constant-time function)، وقم بتحليل JSON فقط بعد التحقق، وسجّل عملية التسليم، وأرجع استجابة 2xx سريعة بعد القبول المتين. تُوقّع Nordlet خوارزمية HMAC فوق النص الخام، وترسله كـ sha256=<hex>، وتعيد محاولات التسليم بتراجع أسي. تعزز إرشادات إخطارات الويب من Stripe ضرورة التحقق من النص الخام غير المُعدّل باستخدام المقارنة الثابتة الوقت.
قم بتشغيل اختبارات سلبية (negative tests): النص والسر الصحيحان، النص الصحيح مع سر خاطئ، تغيير بايت واحد في النص، إعادة تسلسل JSON مع تعديل المسافات البיضاء، رأس مفقود، توقيع مشوه، تسليم قديم مُعاد تشغيله إذا كان النظام يتضمن طابعاً زمنياً، وتوقيع صالح يتم تسليمه إلى اشتراك خاطئ.
معايير النجاح: لا يتم قبول سوى النص الخام والسر الصحيح. التوقيعات غير الصالحة تحصل على استجابة غير 2xx. الحمولات غير الصالحة لا تدخل أبداً إلى قائمة الانتظار المحاسبية. تبقى الأسرار بعيدة عن السجلات العادية. يعترف المعالج بالأمر فقط بعد تسجيل الحدث بشكل متين.
إخطارات الويب المكررة وغير المرتبة
موثوقية التسليم هي مشكلة منفصلة عن عدم تكرار طلبات API، ويجب أن يكون المُستقبل غير متكرر العمليات (idempotent) أيضاً. سلّم نفس الحدث مرتين، وسلّم حدث sale_invoice.paid قبل حدث sale_invoice.issued، وأرجع 500 بعد الحفظ ولكن قبل الاستجابة، وأعد تشغيل حدث عَالَجه المستهلك بالفعل.
تأكد من أن عمليات التسليم المكررة لا تكرر المدفوعات أو تغييرات الحالة أو إجراءات دفتر اليومية، وأن مفتاح إلغاء التكرار يستخدم مُعرف التسليم أو الحدث الخاص بمزود الخدمة عند وجوده (أو مفتاحاً مركباً مُوثقاً، وليس أبداً طابعاً زمنياً عشوائياً)، وأن الأحداث غير المرتبة زمنياً لا تكتب فوق الحالة الأحدث بحالة أقدم، وأن المستهلك يمكنه جلب الحالة الحالية من واجهة برمجة التطبيقات عندما يكون الترتيب غير كافٍ، وأن محاولات المستهلك الفاشلة تُوجّه عبر قائمة انتظار أو مسار الرسائل الميتة (dead-letter path). تحذر Stripe بوضوح من أن ترتيب التسليم غير مضمون وتوصي بتخزين معرفات الأحداث المُعالجَة.
حافظ على خفة نقطة النهاية: تحقق من الشكل، تحقق من التوقيع، احفظ البيانات أو أضفها لقائمة الانتظار، أرسل التأكيد، وأرجع استجابة 2xx. تنتمي عملية المطابقة والإشعارات إلى المعالجة غير المتزامنة (async processing). اختبر ذلك عبر جعل العمليات اللاحقة تنام لفترة تتجاوز مهلة التسليم؛ فالمستقبل الصحيح لا يزال يرسل التأكيد بعد وضع البيانات في قائمة الانتظار المتينة.
الفترات المحاسبية المفتوحة والمقفلة
تفرض Nordlet إقفالات الفترات في وقت الترحيل عبر دفاتر اليومية اليدوية، وتدفقات المستندات، وعمليات الاستيراد، لذا اختبر أداة التحكم في أكثر من مكان واحد. أنشئ مستندات مكافئة مؤرخة في فترة مفتوحة، وفي فترة مقفلة، وعند الحد الفاصل قبيل الإقفال مباشرة، وفي اليوم الأول من الفترة المفتوحة التالية، وبتاريخ مستند صحيح ولكن بتاريخ ترحيل غير صالح إذا كانت واجهة برمجة التطبيقات تفصل بين الاثنين.
بالنسبة لحالة الفترة المقفلة، تأكد من رفض الطلب مع خطأ إقفال الفترة المُوثّق (خطأ تعارض 409 conflict في Nordlet)، وأنه لم يتم كتابة أي أسطر دفترية، ولم يُستهلك أي رقم مستند، ولم ينتقل أي مستند إلى حالة مُرحّل، ولم يتم إطلاق أي إخطار ويب للنجاح. يجب أن تنجح نسخة الفترة المفتوحة بنفس القيم المالية.
اختبار السباق (Race test): ابدأ عملية ترحيل في فترة مفتوحة، وأقفل الفترة في منتصف الطلب، وتأكد من أن عملية الاعتماد لا يمكنها تجاوز القفل. شرط النجاح الحاسم: ألا يهبط الترحيل المُعتمد أبداً في فترة تم إقفالها قبل اعتماد المعاملة.
قابلية التدقيق والمطابقة
لكل عملية تعديل ناجحة، تأكد من وجود الكائن التجاري، ووجود القيد المحاسبي مع تساوي المدين والدائن، ووجود سجل التدقيق، ووجود حدث إخطار الويب أو إمكانية استرجاعها، وأن سجل عمليتك يشير إلى معرف كائن المزود مع إشارة محاولات إعادة التشغيل إلى نفس العملية المنطقية.
لكل عملية تعديل مرفوضة، تأكد من عدم وجود مستند جزئي، وعدم استهلاك أي رقم ما لم يسمح العقد بالحجز، وعدم وجود أي إيصال دفتر يومية، وعدم وجود إخطار ويب للنجاح، وأن الخطأ يحمل معرف طلب للتشخيص. تصف اصطلاحات Nordlet قابلية تدقيق التعديلات والقيود المتوازنة كضمانات للمنصة، حيث يتم فرض التوازن بواسطة مشغل قاعدة بيانات مؤجل (deferred database trigger) وقت الاعتماد بدلاً من تطبيق الكود وحده. حوّل تلك الضمانات إلى استعلامات مطابقة بعد الاختبار بدلاً من الوثوق باستجابة HTTP.
مصفوفة الاختبارات الأساسية
| المجال | إجراء الاختبار | التأكيد المتوقع | معيار النجاح |
|---|---|---|---|
| المصادقة | بلا مفتاح، مفتاح غير صالح، نطاق غير كافٍ | خطأ منظم 401/403؛ بلا آثار جانبية |
جميع المحاولات المرفوضة لا تنشئ أي سجل محاسبي |
| المخطط والقيم المالية | قيمة عشرية أو تاريخ أو حقل مطلوب غير صالح | خطأ تحقق على مستوى الحقل | لا تحدث إعادة محاولة أو كتابة جزئية |
| الترحيل العادي | إنشاء وإصدار فاتورة في فترة مفتوحة | مستند واحد، دفتر يومية متوازن واحد، سجل تدقيق واحد | تتطابق حالة القراءة الخلفية ودفتر اليومية |
| إعادة التشغيل لنفس المفتاح | تكرار نفس التعديل، بنفس المفتاح والحمولة | إعادة تشغيل النتيجة الأصلية؛ لا يوجد تكرار | بقاء معرف الكائن ورقم المستند وتأثير الدفتر والتدقيق مفرداً |
| حمولة مختلفة، نفس المفتاح | إعادة استخدام المفتاح بمبلغ مختلف | رفض إعادة استخدام المفتاح المُوثّق | بقاء السجل الأصلي دون تغيير؛ عدم كتابة أي جديد |
| انقطاع الاتصال | اعتماد، قطع الاتصال، إعادة المحاولة بنفس المفتاح | نتيجة مُعادة التشغيل | أثر جانبي مالي واحد فقط لا غير |
| فترة مقفلة | ترحيل مستند مؤرخ في فترة مقفلة | رفض قفل الفترة | لا دفتر يومية، لا رقم، لا إخطار ويب للنجاح |
| توقيع إخطار الويب | سر خاطئ، نص مُعدّل | استجابة غير 2xx من المُستقبل | قبول النص الخام والسر الصحيحين فقط |
ما سأقوم به أولاً
إذا كان الوقت ضيقاً، قم بتشغيل الاختبارات بالترتيب الذي يكشف عن الأخطاء الأكثر تكلفة. ابدأ بإعادة محاولة الاتصال المقطوع، لأن هذا السيناريو الفردي ينتج معظم التרارات الحقيقية. ثم انتقل إلى ثنائية عدم التكرار لنفس المفتاح والحمولة المختلفة. بعد ذلك، الفترات المقفلة، نظراً لأن الترحيل في شهر مغلق يمثل مشكلة تدقيق تظهر متأخرة. يأتي بعد ذلك التحقق من التوقيع وإخطارات الويب غير المرتبة زمنياً، ويمكن تشغيل مصفوفة المخطط والمصادقة بالكامل بشكل مستمر في CI بمجرد استقرار العميل.
كل شيء آخر في هذه الخطة يدعم تلك النقاط الخمس. اجعلها خضراء في بيئة تجريبية، مع قراءات مطابقة تؤكد الآثار الجانبية، وستعرف أن التكامل آمن قبل أن يلمس سجلاً حقيقياً واحداً. يمكنك إنشاء شركة تجريبية ومفتاح اختبار مقيد النطاق في دقائق معدودة من البدء، وتحقق من الوحدات التي تحتاجها مقابل قائمة الميزات.
FAQ
هل استجابة 2xx كافية لتأكيد نجاح عملية كتابة محاسبية؟
لا. يؤكد رمز الحالة أن الخادم قد أجاب، وليس أن مستنداً واحداً، وتخصيص رقم واحد، وقيد دفتر يومية متوازن واحد موجودة بالفعل. يجب أن تتبع كل اختبارات التعديل قراءة للكائن، وتأثيره المحاسبي، وسجل التدقيق الخاص به. الحالة الخطيرة هي الاتجاه المعاكس: عملية تمت اعتمادها بينما لم يتلقَ العميل الاستجابة على الإطلاق.
هل يجب أن أنشئ مفتاح عدم تكرار جديداً عندما تنتهي مهلة الطلب (timeout)؟
لا، وهذا هو الخطأ الذي يسبب معظم حالات التكرار في الإنتاج. المفتاح يحدد العملية التجارية المنطقية وليس محاولة الشبكة. أعد محاولة استخدام نفس المفتاح، ثم تحقق من التطابق عبر قراءة المورد. مكتبة إعادة المحاولة التي تُنشئ معرف فريد عالمي (UUID) جديداً لكل محاولة تحول فاتورة واحدة مقصودة إلى عمليات كتابة مستقلة متعددة.
ماذا يحدث إذا أعدت استخدام مفتاح عدم تكرار بحمولة مختلفة؟
ترفضه واجهة برمجة التطبيقات الصحيحة بدلاً من تطبيق الحمولة الجديدة بصمت. تُرجع Nordlet الخطأ 422 idempotency_key_reuse وتترك السجل الأصلي دون مساس. يجب أن يتعامل عميلك مع هذا على أنه خطأ برمجي يجب إصلاحه، وليس كحالة يمكن الالتفاف حولها عن طريق توليد مفتاح جديد.
هل إخطارات الويب بديل لقراءة الكائن المُنشأ مرة أخرى؟
لا. يثبت تسليم إخطار الويب عملية الإبلاغ للأنظمة اللاحقة، وليس أن المعاملة تمت بالطريقة التي تتوقعها، كما أن ترتيب التسليم غير مضمون. تحقق من التوقيع فوق النص الخام، وألغِ التكرار بناءً على معرف التسليم أو الحدث، واجلب الحالة الحالية من واجهة برمجة التطبيقات كلما كان ترتيب الأحداث وحده غير كافٍ لتحديد ما تغير.
كيف أختبر الترحيل في فترة محاسبية مقفلة؟
أنشئ مستندات مكافئة في فترة مفتوحة وفي فترة مقفلة، وتأكد من رفض الحالة المقفلة بدون أسطر دفتر يومية، وبدون استهلاك رقم مستند، وبدون انتقال الحالة، وبدون إرسال إخطار ويب للنجاح. ثم شغّل نسخة السباق: ابدأ الترحيل في فترة مفتوحة وأقفل الفترة في منتصف الطلب. يجب ألا يهبط الترحيل المُعتمد أبداً في فترة تم إقفالها قبل اعتماد المعاملة.
هل يمكنني تشغيل اختبارات تكرار ذات حجم كبير في شركة تجريبية؟
نعم. تتصرف الشركة التجريبية مثل الشركة الحقيقية، ويتم تعليمها كبيانات اختبار، ويتم حذفها فوراً بدلاً من البقاء بعد نافذة الاحتفاظ بالبيانات، لذا فهي المكان المناسب لاختبارات التدمير والتكرار. لا يزال استخدام البيئة التجريبية مقاساً ومفوترًا مثل الاستخدام الحقيقي، لذا قم بتخطيط الحجم بدلاً من التكرار بلا توقف.