محتويات الدورة

GraphQL / المتقدم: التنفيذ المحدود والموزع / الدرس 14

الكتابات المتحملة للتكرار والتعارض والمعاملات

احم آثار العمل عند إعادة الطلب بعقد واضح لهوية المحاولة، وكشف تعارض النسخ، وحدود المعاملة.

وقت القراءة التقريبي: 5 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • افصل هوية الطلب والكائن والنسخة التفاؤلية.
  • حلل الطلب المكرر وحد المجال الذري.

صمم لفقد الرد بعد نجاح الحفظ

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

افصل هوية الطلب عن شرط نسخة الكائن

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

graphql حقول تميز هوية المحاولة عن نسخة الكائن
input PublishCourseInput {
  id: ID!
  expectedRevision: Int!
  requestKey: String!
}
type PublishCoursePayload {
  course: Course
  problems: [Problem!]!
}

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

نسق حفظ الأثر ونتيجة الإعادة

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

افحص الإعادة بنموذج محلي محدود النطاق

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

javascript نموذج محلي للتعرف على إعادة الطلب
const seen = new Map();
let revision = 4;
function publish(key, fingerprint) {
  if (seen.has(key)) {
    const old = seen.get(key);
    if (old.fingerprint !== fingerprint) throw new Error("KEY_REUSED");
    return old.result;
  }
  const result = {revision: ++revision};
  seen.set(key, {fingerprint, result});
  return result;
}
console.assert(publish("r1", "c1@4").revision === 5);
console.assert(publish("r1", "c1@4").revision === 5);
console.assert(revision === 5);

لا تزيد الإعادة المطابقة النسخة مرة أخرى في هذه العينة المتزامنة داخل عملية واحدة. لم ينفذ المثال حماية من السباق أو استمراراً أو تعافياً من انهيار.

اختبر النتيجة غير المؤكدة والتعارض

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

الأخطاء الشائعة وإصلاحها

تنشر الإعادة مرتين

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

تمر نسختان من فحص البداية

لماذا يحدث؟
لم ينسق الفحص والكتابة ذرياً.
كيف تصلحه؟
استخدم فرادة ومعاملة دائمتين مناسبتين.
كيف تتجنب تكراره؟
راجع التكرار المتزامن وحدود الانهيار.

تختلط نسخة قديمة بالإعادة

لماذا يحدث؟
دمج تعارض الكائن وهوية الطلب بحقل واحد.
كيف تصلحه؟
عرف النسخة والمفتاح منفصلين.
كيف تتجنب تكراره؟
اختبر التعديل الجديد وإعادة النقل منفصلين.

اختبر فهمك

1. لماذا يفشل المفتاح نفسه بإدخال مختلف؟

اعرض الحل المشروح

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

2. هل يحل تسلسل جذور الطفرة طلبَي HTTP مكررين متزامنين؟

اعرض الحل المشروح

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

أهم ما تعلمته

  • تحمي مفاتيح التكرار والنسخ جانبين مختلفين.
  • لا ينفذ ترتيب الطفرات أمان إعادة دائماً.

المراجع الرسمية