GraphQL / المتقدم: التنفيذ المحدود والموزع / الدرس 15
الاشتراكات والأحداث ودورات التدفق
افصل تنفيذ الاشتراك عن ضمانات توصيل الأحداث، وحدد كيف تستمر الصلاحيات وكيف تحرر الموارد خلال الاتصال الطويل.
في هذه الصفحة
أهداف الدرس
- اشرح تدفق المصدر وتنفيذ الاختيار لكل حدث.
- صمم إعادة الاتصال وإزالة التكرار وإعادة التفويض صراحة.
افصل تدفق الأحداث عن مجرد تكرار القراءة
ينشئ الاشتراك تدفقاً لأحداث المصدر، ثم ينفذ مجموعة الحقول المختارة لإنتاج رد عند كل حدث ذي صلة. تعرف مواصفة GraphQL دلالات اللغة والتنفيذ، لكنها لا تفرض بروتوكول نقل واحداً أو وسيط رسائل معيناً. لتكاملات WebSocket والأحداث المرسلة من الخادم قواعد بروتوكول ودورة حياة مستقلة. مجرد تعريف حقل اشتراك لا يضمن الاحتفاظ بتاريخ دائم، أو توصيل الحدث مرة واحدة بالضبط، أو استعادة ما فات أثناء الانقطاع. قبل اختيار البنية وسلوك العميل، قرر هل الميزة تلميح مباشر تقريبي، أم موجز أحداث قابل للتعافي، أم إشارة يعتمد عليها سير عمل حرج.
اختر حمولة تكفي لتسوية الحالة
يختار الاشتراك التالي معرف الحدث، ومعرف الكائن، ورقم نسخته، حتى يستطيع العميل تسوية العرض الموجود لديه مع الحالة الجديدة. يجب أن يعرف المخطط courseChanged ونوع الحدث الذي يعيده، وعلى الخادم تفويض الوصول إلى نطاق المقرر المطلوب. وفق قواعد اللغة، تحتوي عملية الاشتراك الواحدة حقلاً جذرياً واحداً. أبق حمولة الحدث محدودة، ولا تبث الكائنات الخاصة لكل المشتركين ثم تعتمد على تصفيتها داخل العملاء. تظل صلاحية قراءة الإخراج مهمة عند توصيل الحدث نفسه، خصوصاً إذا تغيرت العضوية أو قواعد ظهور الكائن أثناء استمرار الاتصال.
subscription CourseUpdates($id: ID!) {
courseChanged(id: $id) {
eventId
course { id revision title }
}
}
هذه الحقول جزء من عقد أحداث يضعه التطبيق. تمنح العميل معلومات للتسوية، لكنها لا تنفذ الاحتفاظ بالأحداث في وسيط الرسائل أو إعادة ما فاته منها.
أدر صلاحية الوصول والموارد طوال عمر التدفق
قد لا تبقى نتيجة المصادقة عند إنشاء الاتصال صالحة طوال عمر التدفق. حدد سياسة انتهاء الرمز وإلغائه، وتبدل المستأجر، وتغير أهلية الوصول إلى الكائن. أعد التفويض للأحداث المعنية، أو أنه الاتصال واطلب إعادة إنشائه وفق سياسة موثقة؛ فنجاح المصافحة الأولى لا يمنح وصولاً غير محدود المدة. عند الإكمال أو الإلغاء أو الانقطاع، حرر مستمعي الأحداث ومكرراتها وموارد المصدر المرتبطة بها. قيد عدد الاشتراكات النشطة والرسائل المنتظرة لكل هوية. وللعميل البطيء اختر عمداً إسقاط الرسائل أو دمجها أو قطع الاتصال، بدلاً من مخزن انتظار ينمو بلا حد في ذاكرة العملية.
سو الإشعارات المكررة والمتأخرة
يعامل النموذج المحلي التالي الحدث ذا النسخة باعتباره إشعاراً يساعد على تحديث عرض اصطناعي. يتجاهل معرف الحدث الذي سبق استقباله، ولا يسمح لنسخة أقدم باستبدال نسخة أحدث. قد يحتاج التدفق الحقيقي إلى إعادة قراءة الحالة المعتمدة بعد اكتشاف فجوة؛ فرقم النسخة وحده لا يثبت وصول جميع الأحداث الوسيطة. مجموعة المعرفات هنا محدودة لأن العينة تضم أربعة أحداث فقط، أما سجل إزالة التكرار في التطبيق الفعلي فيحتاج مدة احتفاظ واضحة. لا ينفذ هذا المثال إدخالاً أو إخراجاً غير متزامن، ولا يختبر نقل الاشتراك أو ترتيب رسائله في الشبكة.
const events = [
{id:"e1",revision:5}, {id:"e1",revision:5},
{id:"e3",revision:7}, {id:"e2",revision:6}
];
const seen = new Set();
let revision = 4;
for (const event of events) {
if (seen.has(event.id)) continue;
seen.add(event.id);
revision = Math.max(revision, event.revision);
}
console.assert(revision === 7);
console.assert(seen.size === 3);
تظل النسخة النهائية 7 رغم وصول الحدث الأول مرتين ووصول النسخة 6 بعد النسخة 7. لا تثبت النتيجة اكتمال توصيل الأحداث أو خلو سجلها من الفجوات.
حدد التعافي قبل تقديم ضمانات التحديث المباشر
إذا انقطع النقل، فإن إعادة الاتصال تنشئ تدفقاً جديداً ما لم يدعم التطبيق آلية استئناف موثقة. يحتاج مؤشر الاستئناف إلى دلالات للاحتفاظ والنطاق والانتهاء، مثل مؤشر التصفح. عندما لا توجد إعادة أحداث موثوقة، اقرأ الحالة المعتمدة مجدداً ثم سوها مع الأحداث الواردة ببروتوكول يراعي سباق القراءة والتوصيل. ابدأ باختبارات لمصادر أحداث محلية حتمية تغطي الانقطاع، وانتهاء الصلاحية، والتكرار، وكشف الفجوات، وبطء المستهلك، والتنظيف. لا تعتبر نجاح مخفض متزامن دليلاً على اختبار نقل حي أو وسيط رسائل أو تحويل عند الفشل؛ فكل دمج يحتاج أدلته الخاصة في بيئة مأذون بها.
الأخطاء الشائعة وإصلاحها
تفوت إعادة الاتصال تغييرات مهمة
- لماذا يحدث؟
- اختلط التوصيل المباشر بالإعادة الدائمة.
- كيف تصلحه؟
- استعمل إعادة موثقة أو تسوية معتمدة.
- كيف تتجنب تكراره؟
- اختبر انقطاعاً يضم أحداثاً متعددة.
يستمر مستخدم منتهي في تحديثات خاصة
- لماذا يحدث؟
- فحص التفويض عند المصافحة فقط.
- كيف تصلحه؟
- أعد الأهلية أو أنه وفق الانتهاء.
- كيف تتجنب تكراره؟
- اختبر الإلغاء أثناء تدفق نشط.
تنمو الذاكرة لعميل بطيء
- لماذا يحدث؟
- افتقدت الأحداث المعلقة حداً وسياسة ضغط.
- كيف تصلحه؟
- قيد المخزن واختر دمجاً أو إسقاطاً أو قطعاً.
- كيف تتجنب تكراره؟
- تحقق من التنظيف والحدود معزولاً.
اختبر فهمك
1. ماذا يحل eventId ولا تحله revision وحدها؟
اعرض الحل المشروح
يسمح معرف الحدث الثابت بالتعرف على إعادة الإشعار نفسه، حتى إذا حمل النسخة نفسها من الكائن. أما رقم النسخة فيرتب حالة الكائن وفق العقد الموثق له؛ وقد تشترك أحداث مختلفة في نسخة، أو يؤثر حدث واحد في عدة سجلات. لذلك افصل المعنيين صراحة في العقد. لا يثبت أي من الحقلين وحده توصيلاً موثوقاً للنقل أو وجود سجل أحداث كامل قابل للتدقيق.
2. لماذا يعيد العرض القراءة بعد فجوة نسخ؟
اعرض الحل المشروح
قد تشير الفجوة إلى أن العميل يفتقد تغييرات لازمة لبناء العرض الحالي. إذا لم يوفر الموجز إعادة موثوقة لأحداث محفوظة، فإعادة قراءة المصدر المعتمد أكثر أماناً من اختراع حالات وسيطة مفقودة. سو نتيجة القراءة مع الأحداث التي تصل في الوقت نفسه وفق بروتوكول النسخ الخاص بالتطبيق، واعرض عند الحاجة حالة مؤقتة تبين قدم البيانات بدلاً من ادعاء اكتمال مستمر للتحديثات.
أهم ما تعلمته
- لا تعرف صياغة الاشتراك ضمان نقل دائماً.
- تحتاج الهوية والإعادة والضغط والتنظيف قواعد عمر صريحة.