الخلاصة

  • تضع مسودة HTTPAPI المنتهية الصلاحية دورة حياة Idempotency-Key وسياسة انتهائه ضمن عقد المورد. وتكشف وثائق Stripe وAWS الرسمية أن التعرف إلى المحاولات المتأخرة له حدود خاصة بكل خدمة، وليس ضمانا عاما ينشأ بمجرد إضافة ترويسة.
  • يجب فصل مدة الاحتفاظ بذاكرة منع التكرار عن مدة صلاحية الإذن بإحداث النتيجة. بعد انقضاء نافذة التعرف، تحتاج العملية غير المحسومة إلى مطابقة مع هوية تشغيلية باقية أو إلى مراجعة، لا إلى اعتبارها أمرا جديدا لأن سجل المفتاح اختفى.

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

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

هذه هي المسافة التي تخفيها عبارة «إعادة المحاولة بأمان». الأمان يتوقف على تعريف العملية ونطاق المفتاح ومقارنة الحمولة ومدة الاحتفاظ بالحالة وكيفية التعامل مع الطلبات المتأخرة. لا تستطيع سلسلة عشوائية، مهما كان احتمال تصادمها صغيرا، أن تثبت عدم وقوع أثر سابق. ولا تتحول تلقائيا إلى إذن بإحداث أثر ثان حين يمحى السجل الذي منحها معناها.

تعرض draft-ietf-httpapi-idempotency-key-header-07، المنشورة في 15 أكتوبر 2025، تصورا مفيدا لهذه الحدود. تقترح ترويسة منظمة ذات قيمة نصية، وقواعد لتفرد المفتاح، وبصمة اختيارية للحمولة، ومعاملة مختلفة للتكرار المكتمل والتكرار المتزامن. وتحمّل المورد مسؤولية دورة حياة المفتاح ونشر سياسة انتهاء صلاحيته.

لكن وضع الوثيقة جزء من الدليل، لا هامش يمكن إسقاطه. انتهت صلاحية الإصدار 07 في 18 أبريل 2026. عند تاريخ هذا البحث هو Internet-Draft مؤرشف ومنتهي الصلاحية صادر في سياق مجموعة عمل HTTPAPI، وليس مسودة نشطة أو RFC أو معيارا معتمدا. ارتباط النص بمجموعة عمل لا يثبت موافقة جماعية عليه. تستخدم هذه المقالة دلالاته المقترحة إلى جانب وثائق خدمات قائمة، ولا تنسب إليه التزامات عامة واجبة على كل واجهة HTTP.

غياب الرد ليس دليلا على غياب التنفيذ

يشرح RFC 9110 خاصية عدم تغير الأثر المقصود عند تكرار بعض طرائق HTTP. وهي لا تعني أن السجلات أو الردود متطابقة في كل مرة، ولا أنها توفر تنفيذا واحدا فقط عبر كل الأنظمة المتصلة. لا يصبح POST أو PATCH عشوائي محميا من جميع الآثار المكررة لمجرد وجود Idempotency-Key. يمكن للمورد أن يحدد عقدا مناسبا، لكن العميل يحتاج إلى معرفة ذلك العقد.

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

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

في المعاملة التي تقترحها المسودة، يعيد التكرار بعد اكتمال العملية النتيجة السابقة، سواء كانت نجاحا أو خطأ. أما التكرار أثناء استمرار الأصل، فيواجه تعارضا. وتختلف عنه إعادة استخدام مفتاح مع حمولة مختلفة. تناقش الوثيقة 400 عند غياب مفتاح مطلوب، و422 لعدم تطابق الحمولة، و409 عندما لا تزال العملية الأصلية جارية. هذه اقتراحات في الوثيقة، لا وصف موحد لما تفعله كل الخدمات اليوم.

الأهم أن رسالة الخطأ قد تحمل معرفة تشغيلية ثمينة. إخفاؤها وراء توليد مفتاح جديد لا يحسم وضع الأصل. «لم نحصل على نجاح» عبارة تخص ما يراه العميل؛ «لم يقع أي أثر» عبارة تحتاج إلى دليل من المسار الذي ينفذ العمل.

سياسة الحذف تحدد أين ينتهي الوعد

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

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

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

تعرض AWS في Builders Library مثالا مختلفا عبر EC2. قد تصل محاولة متأخرة بعد أن حذف طرف آخر المورد الذي أنشأه الطلب الأصلي. الحفاظ على رد مكافئ دلاليا يمنع تفسير هذه المحاولة كطلب لإعادة إنشاء المورد. ويصف النص الاحتفاظ بمعرفة الطلب مدة ترتبط بحياة المورد، مع فترة إضافية لوصول المحاولات المتأخرة، ويؤكد اختلاف المتطلبات بين الخدمات والموارد.

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

توصي AWS أيضا بالتنسيق الذري بين تسجيل رمز الطلب والتغييرات التي ينفذها النظام. فهذا يغلق فجوة يستطيع فيها التنفيذ الالتزام دون حفظ وسيلة التعرف إليه. لكنه لا يثبت أن معاملة محلية واحدة أحاطت بكل أثر لاحق في كل مزود أو مستلم. حدود المعاملة يجب أن تبقى واضحة، لا أن تختفي في عبارة «مرة واحدة فقط».

أربع هويات لا تؤدي الوظيفة نفسها

من المفيد فصل مفتاح منع التكرار عن هوية العملية التجارية، وعن هوية الأثر أو المورد الناتج، وعن هوية قصد جديد فعلا. هذا الفصل اقتراح حوكمة في المقالة، وليس مجموعة حقول جديدة يفرضها IETF.

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

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

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

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

قد تكون للمطابقة حدود أيضا. وجود مورد لا يثبت دائما أنه ناتج عن العملية محل البحث، وغيابه لا يثبت أن العمل لم يحدث؛ ربما حذف لاحقا كما في مثال EC2. وسجل يثبت قبول الأمر لا يثبت اكتمال أثره عند الطرف الآخر. لذلك ينبغي وصف ما يحسمه الدليل وما يتركه مفتوحا، بدلا من جعل خانة «تمت التسوية» غطاء لكل الحالات.

وثيقة صغيرة وحدود قرار واضحة

تقرأ هذه المقالة هذه المسألة من المنظور الذي تعرضه ملاحظات heng.lu عن الحد الأدنى للمواصفة وتوطين القرار المستقبلي والتبني الطوعي. ليست الغاية كتابة تعليمات مركزية لكل حالة تشغيلية، بل تحديد معنى الوعد وحدود المعرفة ومن يملك القرار عندما يتغير المستقبل خارج ذاكرة الطلب.

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

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

الخلاصة التشغيلية ليست «احتفظوا بالمفتاح أكثر»، وإن كان ذلك مفيدا أحيانا. إنها «لا تستنتجوا إذنا من فقدان الذاكرة». يستطيع الخادم إنهاء كلفة تخزين رد قديم، لكنه لا يستطيع بذلك وحده إلغاء أثره أو نقل سلطة إعادة إحداثه إلى عامل آلي لا يعرف ما جرى.

المصادر

  1. سجل المسودة وحالتها في IETF Datatracker.
  2. تاريخ إصدارات المسودة.
  3. نص الإصدار 07 بصيغة HTML.
  4. النص المؤرشف للإصدار 07.
  5. المصدر المنظم للإصدار 07.
  6. تعريف مجموعة عمل HTTPAPI.
  7. وثائق مجموعة HTTPAPI.
  8. مستودع العمل الخاص بالمقترح.
  9. سجل النقاشات والمسائل في المستودع.
  10. RFC 9110: دلالات HTTP.
  11. RFC 9457: تفاصيل مشكلات واجهات HTTP.
  12. RFC 8941: الحقول المنظمة.
  13. RFC 9562: المعرّفات الفريدة UUID.
  14. RFC 9111: التخزين المؤقت في HTTP.
  15. Stripe: الطلبات ذات الأثر غير المتكرر.
  16. Stripe: معالجة أخطاء الواجهة منخفضة المستوى.
  17. AWS: جعل المحاولات آمنة باستخدام واجهات تمنع تكرار الأثر.
  18. AWS: المهلات والمحاولات والتراجع مع العشوائية.
  19. heng.lu: الحد الأدنى للمواصفة وتوطين القرار والتبني الطوعي.
  20. heng.lu: مرآة السياسة.