Evenimente de domeniu
Ce este un eveniment de domeniu
Secțiune intitulată „Ce este un eveniment de domeniu”Evenimentele de domeniu sunt mecanismul de decuplare care le permite funcționalităților să comunice fără dependențe directe. În loc ca funcționalitatea A să o apeleze pe funcționalitatea B, funcționalitatea A publică un eveniment, iar funcționalitatea B se abonează la el.
DomainEventBus este un bus de publicare/abonare de tip broadcast, în proces.
Publicatorii apelează publish(event); abonații consumă un flux tipizat
on<T>(). Fiecare eveniment implementează DomainEvent și poartă occurredAt.
Bus-ul rulează în interiorul cc_server. Fiecare publicator și fiecare
abonat activ se află acolo. Niciun client nu vede acest bus. Ce vede un client
este un subset selectat pe care serverul îl retransmite ca și cadre JSON-RPC
notifications/*.
De ce un bus
Secțiune intitulată „De ce un bus”Fără evenimente, fiecare reacție între funcționalități este un import. Calea de notificări ar trebui să importe funcționalitatea de agenți, cea de pull request-uri, tichetele și întâlnirile doar ca să știe când să afișeze un toast — iar fiecare dintre acestea ar trebui apoi să știe că notificările există. Modulul de tichete ar importa pipeline-uri ca un tichet finalizat să poată avansa o rulare. Graful de dependențe se închide într-un nod, iar nucleul partajat încetează să mai fie partajat.
Publicarea unui eveniment rupe acest lanț. Calea de notificări se abonează la douăzeci și unu de clase de evenimente și nu importă niciuna dintre funcționalitățile care le emit. Dispecerul de trigger-e de pipeline se abonează la întregul bus și nu știe nimic despre pull request-uri, tichete sau întâlniri. Agregatele de observabilitate rezumă rezultatele rulărilor fără să pătrundă în logica de trimitere.
Costul este cel obișnuit: un publicator nu poate spune dacă cineva ascultă, iar
un ascultător care nu este niciodată construit rămâne mut în mod silențios.
TicketRemoteSyncHandler este exemplul constant: este declarat, acoperit de
teste și niciodată conectat în producție.
Ce nu este bus-ul
Secțiune intitulată „Ce nu este bus-ul”Merită să fim precisi în privința unui singur lucru pe care bus-ul nu îl deține.
Pista de audit nu este o proiecție a fluxului de evenimente. Fiecare
operație RPC care modifică datele este auditată implicit — RepoOp.audited are
valoarea implicită true, iar o operație se sustrage doar declarând
audited: false, un act deliberat, vizibil chiar pe operație. Dispecerul adaugă
rândul „cine a făcut ce, de unde” imediat după un apel reușit. Nu există
DomainEventAuditBridge. ActivityLogPersister scrie rânduri activity_log
din evenimente ActivityLogged; acesta este un flux separat de auditul RPC.
Bus-ul de evenimente este transportul pentru notificări și pentru automatizare. Nu este sistemul de evidență de referință.
Ce conduce bus-ul
Secțiune intitulată „Ce conduce bus-ul”- Notificări. Douăzeci și unu de clase de evenimente sunt transformate de
server în cadre
notifications/*, înregistrate într-un flux durabil per spațiu de lucru și difuzate sesiunilor conectate. Un cadru al căruiworkspace_idnumește un spațiu de lucru din care utilizatorul sesiunii nu face parte este eliminat pe server; clientul filtrează apoi restul la spațiul de lucru pe care îl are în vedere. - Automatizare bazată pe evenimente. Trigger-ele de pipeline se abonează la bus și pornesc automat pipeline-urile care corespund (vezi mai jos).
- Reacții de ciclu de viață. Crearea unui spațiu de lucru populează agentul CEO și agenții specializați, șabloanele de pipeline incluse și suitele de eval-uri de început. O rulare de agent finalizată reia un pas de pipeline suspendat, închide o sarcină, alimentează supervizorul de obiective, poate trezi un verificator anume și poate declanșa din nou un lider de echipă. Un PR îmbinat sau un spațiu șters declanșează colectarea de gunoi a worktree-urilor.
- Sincronizare între furnizori. Modificările locale ale tichetelor sunt trimise către furnizorii configurați de un coordonator care ascultă cinci evenimente de tichet.
Categorii de evenimente
Secțiune intitulată „Categorii de evenimente”Evenimentele acoperă întreaga suprafață a produsului. La nivel general:
- Spații de lucru, agenți și repo-uri — crearea spațiului de lucru, finalizarea rulărilor, înregistrarea repo-urilor, actualizări de skill-uri
- Pull request-uri — publicare, schimbări de stare, îmbinări, cereri de revizuire, mențiuni, urmărirea PR-urilor proprii, PR-uri detectate extern
- Mesagerie — mesaje, spații și progresul de provisionare a spațiilor
- Tichete — creare, atribuire, reatribuire, detalii, stare și cele trei rezultate finale
- Sarcini — cadre de ciclu de viață secvențiate pentru o singură rulare trimisă, astfel încât clienții să le poată ordona și elimina duplicatele
- Pipeline-uri — doar evenimente finale de rulare (finalizat, anulat, eșuat)
- Observabilitate — intrări de jurnal de activitate și praguri de buget
- Identitate și apartenență — membru adăugat, eliminat, rol schimbat
- Calendar și întâlniri — expirarea autentificării, începerea întâlnirilor și finalizarea înregistrărilor
- Stații — preluare, colectare și închidere neașteptată
Memoria, orchestrarea, documentele de plan, artefactele, aprobările, preluarea sincronizării tichetelor, reîmprospătarea calendarului, îmbinările de worktree-uri, crearea utilizatorilor, invitațiile și revocarea dispozitivelor nu sunt evenimente de domeniu; vezi referința.
Pentru catalogul complet — toate cele 53 de clase concrete de evenimente, payload-urile lor și cei 24 de abonați care le consumă — vezi Referința pentru evenimentele de domeniu. Pagina aceea este inventarul; aceasta este modelul.
Controlul accesului în timp real se bazează pe două mecanisme diferite
Secțiune intitulată „Controlul accesului în timp real se bazează pe două mecanisme diferite”Evenimentele de apartenență și cele de dispozitiv par simetrice, dar nu sunt, ceea ce contează dacă raționezi despre cât de repede își face efectul o revocare.
Revocarea unui dispozitiv chiar îi încheie sesiunile. Serverul supraveghează tabelul de dispozitive asociate și elimină orice sesiune activă al cărei dispozitiv a ieșit din setul activ, în câteva secunde.
Eliminarea unui membru nu închide socketul. WorkspaceMemberRemoved este
consumat: LocalRpcServer și RemoteRelayHost elimină abonamentele la spațiile
de lucru atașate acelui utilizator, iar RemoteEventForwarder își invalidează
cache-ul de apartenență, astfel încât alte cadre pentru acel spațiu de lucru să
nu mai fie trimise. Ceea ce respinge următorul RPC este tot poarta de rol, care
re-rezolvă apartenența la fiecare apel — așa că următoarea lor cerere este
refuzată cu “Not a member of this workspace”. Efectul este imediat pentru orice
încearcă să facă; pur și simplu nu se obține prin închiderea conexiunii lor.
Trigger-ele de pipeline
Secțiune intitulată „Trigger-ele de pipeline”Trigger-ele de pipeline se abonează la evenimente de domeniu și pornesc automat
pipeline-urile care corespund. PipelineTriggerDispatcher ascultă întregul bus,
apoi:
- Iese imediat dacă tipul evenimentului nu este unul pe care știe să îl mapeze la un payload
- Caută trigger-ele activate care corespund acelui tip de eveniment, în fiecare spațiu de lucru
- Filtrează fiecare la propriul spațiu de lucru și aplică filtrul de potrivire a payload-ului
- Pornește o rulare pentru fiecare trigger care supraviețuiește
Constrângerea importantă este pasul 1. Bus-ul transportă 53 de tipuri de
evenimente; selectorul de adăugare a trigger-elor pornește o rulare pentru
aceste paisprezece (ramuri de payload din EventPayloadMapper):
ExternalPrDetected, PullRequestPublished, PullRequestStatusChanged,
PrMerged, MessageReceived, TicketAssigned,
TicketCompleted, TicketFailed, TicketCancelled,
BudgetThresholdCrossed, RepoAdded, MeetingRecordingStopped, SkillUpdated
și SpaceDeleted. Nimic altceva nu poate porni un pipeline.
Cum vede un client toate acestea
Secțiune intitulată „Cum vede un client toate acestea”RemoteEventForwarder traduce evenimentele din clasa notificărilor în cadre și
le trimite prin RPC sesiunilor conectate, unde un mapper de cadre le transformă
în notificări din aplicație. Un client subțire vede așadar o proiecție a
fluxului de evenimente al serverului fără să dețină vreo execuție — ceea ce este
exact ideea din spatele separării clientului subțire.
Totuși, nu orice cadru trimis este o notificare. Fluxul ciclului de viață al sarcinilor și reatribuirea tichetelor sunt trimise în timp real pentru a conduce interfața, dar nu sunt înregistrate în fluxul de notificări și nu afișează niciun toast.
- Pipeline-uri și automatizare: ce pornește un trigger
- Tichete și delegare: atribuirea către un agent vs către o echipă
- Arhitectură: cum se încadrează evenimentele în regula dependențelor
- Referința pentru evenimentele de domeniu: catalogul complet și abonații săi
- Configurează trigger-ele pipeline-urilor
- Configurează notificările