تخطَّ إلى المحتوى

أحداث النطاق

أحداث النطاق آلية فك الارتباط التي تتيح للميزات أن تتواصل من غير اعتماد مباشر. بدل أن تستدعي الميزة أ الميزة ب، تنشر الميزة أ حدثًا وتشترك الميزة ب فيه.

DomainEventBus ناقل بث داخل العملية، بنمط النشر والاشتراك. يستدعي الناشرون publish(event)، ويستهلك المشتركون مجرى on<T>() مُنمَّطًا. كل حدث ينفّذ DomainEvent ويحمل occurredAt.

الناقل يعمل داخل cc_server. كل ناشر وكل مشترك حي يعيش هناك. لا يرى أي عميل هذا الناقل. ما يراه العميل مجموعة منتقاة يعيد الخادم بثّها كإطارات JSON-RPC من النمط notifications/*.

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

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

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

يجدر التدقيق في أمر واحد لا يملكه الناقل.

سجل التدقيق ليس إسقاطًا لمجرى الأحداث. كل عملية RPC مغيّرة تُدقَّق افتراضيًا: قيمة RepoOp.audited الافتراضية هي true، ولا تخرج عملية عن التدقيق إلا بإعلان audited: false، وهو فعل متعمّد ظاهر على العملية نفسها. يُلحِق الموزّع صف «من فعل ماذا، ومن أين» مباشرة بعد الاستدعاء الناجح. لا يوجد DomainEventAuditBridge. يكتب ActivityLogPersister صفوف activity_log من أحداث ActivityLogged، وهذه تغذية منفصلة عن تدقيق RPC.

ناقل الأحداث هو وسيلة نقل الإشعارات والأتمتة. ليس نظام القيد المرجعي.

  • الإشعارات. يحوّل الخادم 21 صنفًا إلى إطارات notifications/* على السلك، ويسجّلها في تغذية دائمة لكل مساحة عمل، ويبثّها إلى الجلسات المتصلة. الإطار الذي يسمّي workspace_id فيه مساحة عمل ليس مستخدم الجلسة عضوًا فيها يُسقَط على الخادم، ثم يصفّي العميل الباقي إلى مساحة العمل التي ينظر إليها.
  • الأتمتة المدفوعة بالأحداث. تشترك مشغّلات خط الأنابيب في الناقل وتبدأ تلقائيًا خطوط الأنابيب المطابقة (انظر أدناه).
  • ردود دورة الحياة. إنشاء مساحة عمل يبذر وكيل CEO والمتخصصين، وقوالب خطوط الأنابيب المضمّنة، وحزم التقييم الابتدائية. اكتمال تشغيل وكيل يستأنف خطوة معلّقة في خط الأنابيب، ويغلق مهمة، ويغذّي مشرف الهدف، ويستطيع إيقاظ مدقق مسمّى، ويستطيع إعادة إطلاق قائد الفريق. طلب سحب مُدمَج أو مساحة محذوفة يطلق جمع مهملات أشجار العمل.
  • المزامنة عبر المزوّدين. تُدفع تغييرات التذاكر المحلية إلى المزوّدين المُعدّين عبر منسّق يستمع إلى خمسة أحداث للتذاكر.

تغطي الأحداث سطح المنتج كله. على مستوى عالٍ:

  • مساحات العمل والوكلاء والمستودعات — إنشاء مساحة العمل، اكتمال التشغيل، تسجيل المستودع، تحديثات المهارة
  • طلبات السحب — النشر، تغيّرات الحالة، الدمج، طلبات المراجعة، الإشارات، مراقبة طلب السحب المؤلَّف، طلبات السحب المكتشفة خارجيًا
  • المراسلة — الرسائل، المساحات، تقدّم تجهيز المساحة
  • التذاكر — الإنشاء، الإسناد، إعادة الإسناد، التفاصيل، الحالة، والنتائج النهائية الثلاث
  • المهام — إطارات دورة حياة متسلسلة لتشغيل مُرسَل واحد، حتى يستطيع العملاء ترتيبها وإزالة تكرارها
  • خطوط الأنابيب — أحداث التشغيل النهائية فقط (مكتمل، ملغى، فاشل)
  • الرصد — بنود سجل النشاط وعتبات الميزانية
  • الهوية والعضوية — إضافة عضو، إزالته، تغيّر الدور
  • التقويم والاجتماعات — انتهاء صلاحية المصادقة، بدء الاجتماعات، انتهاء التسجيلات
  • المنصات — التولّي، الاسترداد، الإغلاق غير المتوقع

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

للفهرس الكامل — أصناف الأحداث الملموسة كلها وعددها 53، وحمولاتها، و24 مشتركًا يستهلكونها — انظر مرجع أحداث النطاق. تلك الصفحة هي الجرد، وهذه هي النموذج.

التحكم الحي في الوصول يسلك آليتين مختلفتين

قسم بعنوان “التحكم الحي في الوصول يسلك آليتين مختلفتين”

تبدو أحداث العضوية وأحداث الجهاز متناظرة، وهي ليست كذلك، وهذا يهم إن كنت تقدّر سرعة سريان سحب الوصول.

إلغاء الجهاز يُنهي جلساته. يراقب الخادم جدول الأجهزة المقترنة، ويُسقط خلال ثوانٍ أي جلسة حيّة خرج جهازها من المجموعة النشطة.

إزالة عضو لا تغلق المقبس. يُستهلك WorkspaceMemberRemoved: يُسقط LocalRpcServer وRemoteRelayHost اشتراكات مساحات العمل المرتبطة بذلك المستخدم، ويُبطل RemoteEventForwarder ذاكرة عضويته المؤقتة حتى لا تُدفع إطارات لاحقة تخص تلك المساحة. ما يرفض استدعاء RPC التالي يبقى بوابة الدور، وهي تعيد حل العضوية عند كل استدعاء — فيُرفض طلبهم التالي بـ«لست عضوًا في مساحة العمل هذه». الأثر فوري على أي شيء يحاولون فعله، غير أنه لا يتحقق بقطع الاتصال عنهم.

تشترك مشغّلات خط الأنابيب في أحداث النطاق وتبدأ تلقائيًا خطوط الأنابيب المطابقة. يستمع PipelineTriggerDispatcher إلى الناقل كله، ثم:

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

القيد المهم هو الخطوة 1. يحمل الناقل 53 نوعًا، ويبدأ منتقي «إضافة مشغّل» تشغيلًا لأربعة عشر نوعًا (فروع حمولة EventPayloadMapper): ExternalPrDetected، PullRequestPublished، PullRequestStatusChanged، PrMerged، MessageReceived، TicketAssigned، TicketCompleted، TicketFailed، TicketCancelled، BudgetThresholdCrossed، RepoAdded، MeetingRecordingStopped، SkillUpdated وSpaceDeleted. لا شيء سواها يستطيع بدء خط أنابيب.

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

ليس كل إطار مدفوع إشعارًا. مجرى دورة حياة المهمة وإعادة إسناد التذكرة يُمرَّران مباشرة لقيادة الواجهة، لكنهما لا يُسجَّلان في تغذية الإشعارات ولا يرفعان إشعارًا منبثقًا.