Nordlet

← الأساسيات / الشروحات

ما هي المعاملة المتطابقة (Idempotency)؟ ولماذا تحتاجها واجهات برمجة تطبيقات المحاسبة والمدفوعات

كيف يؤدي الطلب المعاد إلى إنشاء فاتورة مكررة، وما الذي يضمنه مفتاح التطابق، وأنماط الفشل التي يجب التعامل معها، وكيفية تطبيق ذلك بشكل صحيح.

تكون العملية متطابقة (idempotent) إذا كان تنفيذها مرتين يعطي نفس تأثير تنفيذها مرة واحدة. تعد قراءة السجلات عملية متطابقة بطبيعتها، أما إنشاء فاتورة فليس كذلك؛ إذ إن استدعاء هذه العملية مرتين يعني الحصول على فاتورتين، وحسابين ذمم مدينة (receivables)، وعميل يتساءل عن سبب فوترته مرتين.

تكتسب هذه الفجوة أهميتها لأن الشبكات تفشل بطريقة محددة ومزعجة: ينجح الطلب، ولكن يُفقد الرد. يرى العميل مهلة منتهية (timeout) ولا يمكنه التمييز بين طلب "لم يصل أبداً" وطلب "وصل ونفذ وفُقد الرد". الخيار الآمن الوحيد بالنسبة للعميل هو إعادة المحاولة، وهذه الإعادة هي ما يؤدي إلى التكرار.

لماذا تجعل المحاسبة الأمر أسوأ؟

في معظم الأنظمة، يُعد التكرار مجرد إزعاج، ولكن في دفتر الأستاذ (ledger)، يصبح مشكلة تراكمية:

  • تستهلك الفاتورة المكررة رقماً من سلسلة متصلة بلا فجوات (gapless sequence)، لذا فإن حذفها ليس خياراً مطروحاً؛ فمبدأ عدم القابلية للتغيير يعني أن تصحيحها يتطلب إشعار دائن (credit note)، وهو مستند يراه عميلك.
  • تُرحّل الفاتورة المكررة قيود اليومية، ونتيجة لذلك تظهر الإيرادات وضريبة القيمة المضافة والذمم المدينة بقيم مبالغ فيها إلى أن يلاحظ أحدهم ذلك.
  • تدخل الفاتورة في إقرار ضريبة القيمة المضافة وفي سجلات (i.SAF) في ليتوانيا.
  • إذا أدت الفاتورة إلى تشغيل عملية دفع، فهذا يعني أن أموالاً قد تحركت بالفعل.

ولا يجديك نفعاً الاكتفاء بالقول "تحقق من وجود تكرار"، فوجود فاتورتين منفصلتين حقاً لنفس العميل وبنفس المبلغ وفي نفس اليوم هو أمر طبيعي تماماً. لا يستطيع النظام استنتاج النية من المحتوى، بل يجب على العميل التصريح بها صراحة.

كيف تعمل مفاتيح التطابق؟

يُنشئ العميل مفتاحاً فريداً لكل عملية منطقية ويرسله مع الطلب:

POST /v1/sales/invoices/create
Idempotency-Key: 8f14e45f-ea1b-4c2b-9f3a-2d7c1e0b5a91

عندها يضمن الخادم ما يلي:

  1. الطلب الأول بهذا المفتاح - تتم معالجته بشكل طبيعي، وتُخزن النتيجة المقابلة لهذا المفتاح.
  2. إعادة المحاولة بنفس المفتاح وبنفس الحمولة (payload) - لا يُعاد تنفيذ الطلب، بل يُعاد الرد المخزن.
  3. نفس المفتاح ولكن بحمولة مختلفة - يتم رفض الطلب. يُعد المفتاح إقراراً بأن هذه هي نفس العملية، ووجود محتوى مختلف يعني أنها ليست كذلك، كما أن إعادة النتيجة القديمة بصمت تكون أسوأ من حدوث خطأ.
  4. إعادة المحاولة بينما لا يزال الطلب الأصلي قيد التنفيذ - يتم رفض الطلب بخطأ قابل لإعادة المحاولة بدلاً من تنفيذه بالتزامن.

النقطة الرابعة هي التي تتخلف التطبيقات الساذجة عن معالجتها. فالعميل الذي تنتهي مهلته بعد 5 ثوانٍ ويعيد المحاولة عند الثانية السادسة سيصطدم بطلبه الخاص الذي لا يزال قيد التنفيذ؛ وبدون حماية التزامن، سيمضي الطلبان معاً وتحصل على التكرار الذي وُجدت الآلية لمنعه أساساً.

توليد المفاتيح بشكل صحيح

يجب أن يحدد المفتاح العملية وليس محاولة الإرسال:

  • صحيح: مُعرّف فريد عالمياً (UUID) يُنشئ مرة واحدة عندما ينقر المستخدم على "إصدار فاتورة"، ويُعاد استخدامه في كل محاولة لإعادة تلك النقرة.
  • صحيح: مفتاح حتمي مشتق من نطاق عملك الخاص مثل order-1041-invoice.
  • خطأ: مُعرّف فريد عالمياً (UUID) جديد لكل محاولة بروتوكول HTTP. فكل محاولة ستحصل على مفتاح جديد، وبذلك تكون كل محاولة عملية جديدة، وتكون كمن لم ينفذ شيئاً البداية.
  • خطأ: تجزئة (hash) الحمولة. ففي هذه الحالة، ستتداخل عمليتان متطابقتان شرعاً، وتُبتلع الثانية بصمت.

تحتاج المفاتيح إلى فترة احتفاظ تكفي لتغطية نوافذ إعادة المحاولة الواقعية وانقطاعات العملاء، لا أن تُحتفظ بها إلى الأبد.

ما الذي لا تحله هذه الآلية؟

يحمي التطابق من التنفيذ المكرر لنفس الطلب، ولكنه لا يحمي من:

  • قيام مستخدمين مختلفين بإنشاء نفس الفاتورة من جلستين مختلفتين، فهذه مشكلة تتعلق بقواعد العمل، وتُحل بقيود التفرد مثل السماح بفاتورة واحدة لكل طلب.
  • التكرار المنطقي باستخدام مفاتيح مختلفة.
  • عدم الحتمية داخل العملية نفسها؛ فإذا أنشأ معالج الطلبات طابعاً زمنياً أو رقماً عشوائياً، فإن الرد المخزن يلتقط القيمة الأولى، وهو السلوك المرغوب ولكنه يستحق الفهم.

تُعد هذه الآلية مكملاً لقيود قاعدة البيانات وليست بديلاً عنها. يستخدم دفتر الأستاذ في Nordlet كتاهما: تمنع مفاتيح التطابق الطلبات المعاد إرسالها، بينما تمنع الفهارس الفريدة تكرار دفعات التسوية لكل معرف صرف، وتكرار فواتير الشراء لكل مورد ورقم مستند، وتكرار عمليات الإهلاك لكل أصل وفترة مالية.

كيف تطبق Nordlet هذه الآلية؟

أرسل ترويسة Idempotency-Key مع أي طلب يغير الحالة، على أن تكون سلسلة نصية غير فارغة لا تتجاوز 255 حرفاً.

يُنفذ الطلب الأول بمفتاح معين وتُخزن نتيجته. أما إعادة المحاولة بنفس المفتاح وبنفس الحمولة فتعيد الرد المخزن دون إعادة التنفيذ، وبذلك تُنشأ الفاتورة مرة واحدة بالضبط بغض النظر عن عدد مرات تكرار الاستدعاء.

هناك حالتا فشل صريحتان وليست صامتتان:

  • نفس المفتاح، بحمولة مختلفة ← يُرفض الطلب: "Idempotency-Key was already used with a different request payload." تلتقط هذه الحالة الخطيرة حقاً التي يعيد فيها العميل استخدام مفتاح مع تغيير المبلغ.
  • نفس المفتاح، والطلب الأصلي لا يزال قيد التنفيذ ← يُرفض بوصفه قابلاً لإعادة المحاولة: "A request with this Idempotency-Key is still being processed, retry shortly." لا يوجد تنفيذ مزدوج متزامن.

تُصنف المفاتيح نطاقياً لكل شركة على حدة، لذا فإن مستأجرين (tenants) يُنشئان نفس المُعرّف الفريد (UUID) لن يتداخلا أبداً.

يعمل الضمان التكميلي في الاتجاه المعاكس. تسليم خطافات الويب (Webhooks) يتم بنظام مرة واحدة على الأقل (at-least-once)، مما يعني أن نقطة النهاية الخاصة بك ستتلقى أحياناً نفس الحدث مرتين، وذلك بعد انتهاء مهلة بينما كان التسليم قد نجح بالفعل، أو عند إعادة التسليم. يحمل كل حدث مُعرّفاً، ويجب على معالج الأحداث لديك تسجيل المُعرّفات التي عُولجت وتجاهل المكرر منها. التطابق هو خاصية يحتاجها طرفا عملية التكامل؛ ويوضح دليل اتفاقيات واجهات برمجة التطبيقات (API conventions guide) جانب الطلبات بالتفصيل.

FAQ

ما هو مفتاح التطابق (idempotency key)؟

هو مُعرّف يُنشئه العميل ويُرسل مع الطلب ليسمح للخادم بالتعرف على محاولة إعادة لنفس العملية المنطقية. يُنفذ الطلب الأول، بينما تعيد عمليات إعادة المحاولة بنفس المفتاح النتيجة المخزنة بدلاً من إعادة التنفيذ.

لماذا تحتاج واجهات برمجة تطبيقات المحاسبة إلى التطابق؟

لأن الكتابة المكررة تنشئ مستنداً حقيقياً له عواقب حقيقية؛ مثل فاتورة ثانية تستهلك رقماً تسلسلياً، وتُرحّل إلى دفتر الأستاذ، وتدخل في إقرار ضريبة القيمة المضافة. وخلافاً لعمليات القراءة المكررة، لا يمكن حذف المستند ببساطة، بل يجب تصحيحه بإشعار دائن.

هل يجب أن أنشئ مفتاحاً جديداً لكل محاولة إعادة؟

لا، فهذا يقضي على الآلية برمتها. أنشئ مفتاحاً واحداً لكل عملية منطقية وأعد استخدامه في كل محاولة لإعادة تلك العملية. وجود مفتاح جديد لكل محاولة يعني معاملة كل محاولة كعملية جديدة.

ماذا يحدث إذا أعدت استخدام مفتاح مع حمولة مختلفة؟

يُرفض الطلب. يؤكد المفتاح أن هذه هي نفس العملية، لذا فإن تغير محتوى الجسم يعني أن هناك خطأ ما، وغالباً ما يكون خطأ في إعادة استخدام المفتاح من جانب العميل. أما إرجاع النتيجة السابقة بصمت فسيكون أمراً أسوأ.

هل يمنع التطابق جميع حالات التكرار؟

لا. فهو يمنع التنفيذ المكرر لنفس الطلب فقط. أما قيام مستخدمين مختلفين وبشكل مستقل بإنشاء نفس الفاتورة فيعني وجود طلبين مختلفين، وهي مشكلة تخص قواعد العمل وتُحل عبر قيود التفرد، وليس شيئاً يمكن لمفتاح التطابق رصده.