رفتن به محتوا

رویدادهای دامنه

رویدادهای دامنه سازوکار جداسازی‌ای هستند که به قابلیت‌ها امکان می‌دهند بدون وابستگی مستقیم با هم ارتباط برقرار کنند. به‌جای آنکه قابلیت A قابلیت B را فراخوانی کند، قابلیت A رویدادی منتشر می‌کند و قابلیت B در آن مشترک می‌شود.

DomainEventBus یک گذرگاه انتشار/اشتراک پخش‌همگانی درون‌فرایندی است. ناشران publish(event) را فراخوانی می‌کنند؛ مشترکان یک جریان نوع‌دار on<T>() را مصرف می‌کنند. هر رویداد DomainEvent را پیاده‌سازی می‌کند و occurredAt را با خود دارد.

گذرگاه درون cc_server اجرا می‌شود. هر ناشر و هر مشترک زنده همان‌جا زندگی می‌کند. هیچ کلاینتی این گذرگاه را نمی‌بیند. آنچه کلاینت می‌بیند زیرمجموعه‌ای گزینش‌شده است که سرور آن را به‌صورت فریم‌های JSON-RPC با نام notifications/* بازپخش می‌کند.

بدون رویدادها، هر واکنش میان‌قابلیتی یک واردکردن است. مسیر اعلان‌ها باید فقط برای اینکه بداند کِی یک اعلان شناور نشان دهد، قابلیت عامل‌ها، قابلیت pull request، تیکتینگ و جلسه‌ها را وارد کند — و آن‌وقت هرکدام از آن‌ها هم باید از وجود اعلان‌ها باخبر باشد. تیکتینگ باید پایپ‌لاین‌ها را وارد کند تا یک تیکت کامل‌شده بتواند یک اجرا را جلو ببرد. گراف وابستگی گره می‌خورد و هستهٔ مشترک دیگر مشترک نمی‌ماند.

انتشار یک رویداد این چرخه را می‌شکند. مسیر اعلان‌ها در بیست‌ویک کلاس رویداد مشترک می‌شود و هیچ‌یک از قابلیت‌هایی که آن‌ها را برمی‌انگیزند وارد نمی‌کند. اعزام‌کنندهٔ تریگر پایپ‌لاین در کل گذرگاه مشترک می‌شود و هیچ چیزی دربارهٔ pull requestها، تیکت‌ها یا جلسه‌ها نمی‌داند. رصدپذیری نتایج اجرا را بدون دست بردن در اعزام تجمیع می‌کند.

هزینه‌اش همان هزینهٔ همیشگی است: ناشر نمی‌تواند بفهمد کسی به آن گوش می‌دهد یا نه، و شنونده‌ای که هرگز ساخته نمی‌شود بی‌صدا بی‌اثر می‌ماند. TicketRemoteSyncHandler نمونهٔ همیشگی این وضع است: اعلام شده، تست‌ها آن را پوشش می‌دهند، و هرگز در محیط تولید سیم‌کشی نمی‌شود.

ارزشش را دارد که دربارهٔ یک چیز که گذرگاه مالک آن نیست دقیق باشیم.

ردپای حسابرسی فرافکنشی از جریان رویداد نیست. هر عملیات RPC تغیردهنده به‌طور پیش‌فرض حسابرسی می‌شود — RepoOp.audited به‌طور پیش‌فرض true است و یک عملیات تنها با اعلام audited: false از آن کنار می‌کشد، اقدامی آگاهانه که روی خود عملیات دیده می‌شود. اعزام‌کننده بلافاصله پس از یک فراخوانی موفق، سطر «چه کسی چه کاری، از کجا» را می‌افزاید. DomainEventAuditBridge وجود ندارد. ActivityLogPersister سطرهای activity_log را از رویدادهای ActivityLogged می‌نویسد؛ آن جریانی جداست از حسابرسی RPC.

گذرگاه رویداد همان مسیر انتقال برای اعلان‌ها و خودکارسازی است. اما سیستم دفترداری مرجع نیست.

گذرگاه چه چیزهایی را به حرکت درمی‌آورد

بخش با عنوان “گذرگاه چه چیزهایی را به حرکت درمی‌آورد”
  • اعلان‌ها. سرور بیست‌ویک کلاس رویداد را به فریم‌های شبکه‌ای notifications/* تبدیل می‌کند، آن‌ها را در یک خوراک پایدار به‌ازای هر فضای کاری ثبت می‌کند و به نشست‌های متصل پخش می‌کند. فریمی که workspace_id آن به فضای کاری‌ای اشاره کند که کاربر نشست عضو آن نیست، در سرور حذف می‌شود؛ سپس کلاینت باقی را به فضای کاری‌ای که در حال مشاهدهٔ آن است فیلتر می‌کند.
  • خودکارسازی رویدادمحور. تریگرهای پایپ‌لاین در گذرگاه مشترک می‌شوند و پایپ‌لاین‌های منطبق را خودکار شروع می‌کنند (پایین را ببینید).
  • واکنش‌های چرخهٔ عمر. ساختن یک فضای کاری، CEO و عامل‌های متخصص آن، قالب‌های پایپ‌لاین داخلی و مجموعه‌های ارزیابی آغازین را می‌کارد. یک اجرای کامل‌شدهٔ عامل، گام پایپ‌لاین معلق‌شده را از سر می‌گیرد، یک وظیفه را می‌بندد، ناظر هدف را تغذیه می‌کند، می‌تواند یک بررسی‌کنندهٔ نام‌برده را بیدار کند و می‌تواند رهبر تیم را دوباره برانگیزد. ادغام یک PR یا حذف یک فضا، جمع‌آوری زبالهٔ worktree را راه می‌اندازد.
  • همگام‌سازی میان سرویس‌دهنده‌ها. تغییرات محلی تیکت‌ها با یک هماهنگ‌کننده که به پنج رویداد تیکت گوش می‌دهد، به سرویس‌دهنده‌های تیکت پیکربندی‌شده فرستاده می‌شود.

رویدادها سراسر سطح محصول را در بر می‌گیرند. در یک نگاه کلی:

  • فضاهای کاری، عامل‌ها و مخزن‌ها — ساخت فضای کاری، اتمام اجرا، ثبت مخزن، به‌روزرسانی مهارت‌ها
  • Pull requestها — انتشار، تغییر وضعیت، ادغام‌ها، درخواست‌های بازبینی، منشن‌ها، پایش PRهای تألیف‌شده، PRهای شناسایی‌شده از بیرون
  • پیام‌رسانی — پیام‌ها، فضاها و پیشرفت تأمین فضا
  • تیکت‌ها — ایجاد، تخصیص، تخصیص مجدد، جزئیات، وضعیت و سه پیامد پایانی
  • وظیفه‌ها — فریم‌های چرخهٔ عمر مرتب‌شده برای یک اجرای اعزام‌شده، تا کلاینت‌ها بتوانند آن‌ها را مرتب و تکراری‌زدایی کنند
  • پایپ‌لاین‌ها — فقط رویدادهای پایانی اجرا (کامل‌شده، لغوشده، ناموفق)
  • رصدپذیری — ورودی‌های گزارش فعالیت و آستانه‌های بودجه
  • هویت و عضویت — افزودن عضو، حذف عضو، تغییر نقش
  • تقویم و جلسه‌ها — انقضای احراز هویت، شروع جلسه‌ها و پایان ضبط‌ها
  • ریگ‌ها — تحویل گرفتن، بازپس‌گیری و بسته‌شدن غیرمنتظره

حافظه، ارکستراسیون، اسناد برنامه، مصنوعات، تأییدها، دریافت همگام‌سازی تیکت، بازتازه‌سازی تقویم، ادغام‌های worktree، ساخت کاربر، دعوت‌ها و لغو دستگاه رویداد دامنه نیستند؛ مرجع را ببینید.

برای فهرست کامل — همهٔ ۵۳ کلاس رویداد مشخص، بار داده‌هایشان و ۲۴ مشترکی که آن‌ها را مصرف می‌کنند — مرجع رویدادهای دامنه را ببینید. آن صفحه سیاهه است؛ این صفحه مدل.

کنترل دسترسی زنده بر دو سازوکار متفاوت سوار است

بخش با عنوان “کنترل دسترسی زنده بر دو سازوکار متفاوت سوار است”

رویدادهای عضویت و دستگاه متقارن به نظر می‌رسند و چنین نیستند، و این اگر دربارهٔ سرعت اثرگذاری یک لغو استدلال می‌کنید اهمیت دارد.

لغو یک دستگاه، نشست‌های آن را واقعاً پایان می‌دهد. سرور جدول دستگاه‌های جفت‌شده را زیر نظر دارد و هر نشست زنده‌ای را که دستگاهش از مجموعهٔ فعال خارج شده باشد، ظرف چند ثانیه قطع می‌کند.

حذف یک عضو سوکت را نمی‌بندد. WorkspaceMemberRemoved مصرف می‌شود: LocalRpcServer و RemoteRelayHost اشتراک‌های فضای کاری متصل آن کاربر را می‌اندازند و RemoteEventForwarder کش عضویت خود را باطل می‌کند تا فریم‌های بعدی برای آن فضای کاری فرستاده نشوند. آنچه RPC بعدی را رد می‌کند همچنان دروازهٔ نقش است، که عضویت را در هر فراخوانی دوباره حل می‌کند — پس درخواست بعدی آن‌ها با «Not a member of this workspace» رد می‌شود. اثر آن برای هر کاری که بخواهند انجام دهند فوری است؛ فقط با قطع کردن ارتباطشان به‌دست نمی‌آید.

تریگرهای پایپ‌لاین در رویدادهای دامنه مشترک می‌شوند و پایپ‌لاین‌های منطبق را خودکار شروع می‌کنند. PipelineTriggerDispatcher به کل گذرگاه گوش می‌دهد و سپس:

  1. اگر نوع رویداد از آن‌هایی نباشد که می‌داند چطور به بار داده نگاشت شوند، بلافاصله بازمی‌گردد
  2. تریگرهای فعال منطبق با آن نوع رویداد را در همهٔ فضاهای کاری جست‌وجو می‌کند
  3. هرکدام را به فضای کاری خودش فیلتر می‌کند و فیلتر تطبیق بار داده‌اش را اعمال می‌کند
  4. برای هر تریگری که باقی می‌ماند یک اجرا شروع می‌کند

محدودیت مهم گام ۱ است. گذرگاه ۵۳ نوع رویداد را حمل می‌کند؛ انتخابگر افزودن تریگر برای این چهارده مورد یک اجرا شروع می‌کند (شاخه‌های بار دادهٔ EventPayloadMapper): ExternalPrDetected، PullRequestPublished، PullRequestStatusChanged، PrMerged، MessageReceived، TicketAssigned، TicketCompleted، TicketFailed، TicketCancelled، BudgetThresholdCrossed، RepoAdded، MeetingRecordingStopped، SkillUpdated و SpaceDeleted. هیچ چیز دیگری نمی‌تواند یک پایپ‌لاین را شروع کند.

کلاینت چگونه هر یک از این‌ها را می‌بیند

بخش با عنوان “کلاینت چگونه هر یک از این‌ها را می‌بیند”

RemoteEventForwarder رویدادهای کلاس اعلان را به فریم‌های شبکه‌ای ترجمه می‌کند و آن‌ها را روی RPC به نشست‌های متصل می‌فرستد، جایی که یک نگاشت‌گر فریم آن‌ها را به اعلان‌های درون‌برنامه‌ای تبدیل می‌کند. بنابراین یک کلاینت سبک فقط فرافکنشی از جریان رویداد سرور را می‌بیند، بدون آنکه مالک هیچ اجرایی باشد — که تمام هدف تفکیک کلاینت سبک است.

با این حال، هر فریم فرستاده‌شده یک اعلان نیست. جریان چرخهٔ عمر وظیفه و تخصیص مجدد تیکت به‌صورت زنده برای به حرکت درآوردن رابط کاربری فرستاده می‌شوند، اما در خوراک اعلان‌ها ثبت نمی‌شوند و اعلان شناوری نشان نمی‌دهند.