Eventos de dominio
Qué es un evento de dominio
Sección titulada «Qué es un evento de dominio»Los eventos de dominio son el mecanismo de desacoplamiento que permite que las funcionalidades se comuniquen sin depender directamente unas de otras. En lugar de que la funcionalidad A llame a la funcionalidad B, la funcionalidad A publica un evento y la funcionalidad B se suscribe a él.
El DomainEventBus es un bus de publicación/suscripción con difusión y en
proceso. Quien publica llama a publish(event); quien se suscribe consume un
flujo tipado on<T>(). Todos los eventos implementan DomainEvent y llevan
occurredAt.
El bus se ejecuta dentro de cc_server. Tanto quien publica como quien está
suscrito en vivo residen ahí. Ningún cliente ve este bus. Lo que ve un cliente
es un subconjunto seleccionado que el servidor reemite como tramas JSON-RPC
notifications/*.
Por qué hace falta un bus
Sección titulada «Por qué hace falta un bus»Sin eventos, cada reacción entre funcionalidades sería una importación. La ruta de notificaciones tendría que importar la funcionalidad de agentes, la de pull requests, la de tickets y la de reuniones solo para saber cuándo mostrar un aviso, y cada una de ellas tendría entonces que saber que existen las notificaciones. La de tickets importaría la de pipelines para que un ticket completado pudiera hacer avanzar una ejecución. El grafo de dependencias se cierra en un nudo y el kernel compartido deja de ser compartido.
Publicar un evento rompe esa dinámica. La ruta de notificaciones se suscribe a veintiuna clases de evento y no importa ninguna de las funcionalidades que los emiten. El despachador de disparadores de pipeline se suscribe a todo el bus y no sabe nada de pull requests, tickets ni reuniones. La observabilidad agrega resultados de ejecuciones sin meterse en el despacho.
El coste es el de siempre: quien publica no puede saber si alguien está
escuchando, y un suscriptor que nunca se instancia queda inerte en silencio.
TicketRemoteSyncHandler es el ejemplo permanente: está declarado, tiene
cobertura de tests y nunca se conecta en producción.
Lo que el bus no es
Sección titulada «Lo que el bus no es»Conviene ser precisos sobre una cosa que el bus no posee.
El registro de auditoría no es una proyección del flujo de eventos. Toda
operación RPC que muta estado se audita de forma predeterminada: RepoOp.audited
vale true por omisión y una operación solo queda exenta si declara
audited: false, un acto deliberado y visible en la propia operación. El
despachador añade la fila de «quién hizo qué y desde dónde» justo después de una
llamada correcta. No existe ningún DomainEventAuditBridge.
ActivityLogPersister escribe filas de activity_log a partir de eventos
ActivityLogged; ese es un flujo distinto del de la auditoría RPC.
El bus de eventos sí es el transporte de las notificaciones y de la automatización. No es el sistema de registro contable.
Lo que el bus sí impulsa
Sección titulada «Lo que el bus sí impulsa»- Notificaciones. El servidor convierte veintiuna clases de evento en tramas
notifications/*, las registra en un flujo duradero por espacio de trabajo y las difunde a las sesiones conectadas. Una trama cuyoworkspace_idindique un espacio de trabajo del que el usuario de la sesión no es miembro se descarta en el servidor; el cliente filtra después el resto según el espacio de trabajo que esté viendo. - Automatización basada en eventos. Los disparadores de pipeline se suscriben al bus e inician automáticamente los pipelines que coinciden (ver más abajo).
- Reacciones del ciclo de vida. Al crear un espacio de trabajo se aprovisionan sus agentes CEO y especialistas, las plantillas de pipeline integradas y las suites de evaluación iniciales. Una ejecución de agente completada reanuda un paso de pipeline suspendido, cierra una tarea, alimenta al supervisor de objetivos, puede despertar a un verificador con nombre y puede volver a activar a un líder de equipo. Una PR fusionada o un espacio eliminado activa la recolección de basura de los worktrees.
- Sincronización entre proveedores. Un coordinador que escucha cinco eventos de tickets envía los cambios locales de tickets a los proveedores configurados.
Categorías de eventos
Sección titulada «Categorías de eventos»Los eventos abarcan toda la superficie del producto. A grandes rasgos:
- Espacios de trabajo, agentes y repos — creación de espacios de trabajo, finalización de ejecuciones, registro de repos, actualizaciones de skills
- Pull requests — publicación, cambios de estado, fusiones, solicitudes de revisión, menciones, seguimiento de PRs propias, PRs detectadas externamente
- Mensajería — mensajes, espacios y progreso de aprovisionamiento de espacios
- Tickets — creación, asignación, reasignación, detalles, estado y los tres resultados terminales
- Tareas — tramas secuenciadas del ciclo de vida para una ejecución despachada, para que los clientes puedan ordenarlas y eliminar duplicados
- Pipelines — solo eventos terminales de ejecución (completado, cancelado, fallido)
- Observabilidad — entradas del registro de actividad y umbrales de presupuesto
- Identidad y pertenencia — miembro añadido, eliminado, rol cambiado
- Calendario y reuniones — caducidad de la autenticación, inicio de reuniones y fin de grabaciones
- Rigs — toma de control, recuperación y cierre inesperado
La memoria, la orquestación, los documentos de plan, los artefactos, las aprobaciones, la entrada de sincronización de tickets, la actualización del calendario, las fusiones de worktrees, la creación de usuarios, las invitaciones y la revocación de dispositivos no son eventos de dominio; consulta la referencia.
Para ver el catálogo completo —las 53 clases de evento concretas, sus cargas útiles y los 24 suscriptores que las consumen—, consulta la referencia de eventos de dominio. Esa página es el inventario; esta es el modelo.
El control de acceso en vivo usa dos mecanismos distintos
Sección titulada «El control de acceso en vivo usa dos mecanismos distintos»Los eventos de pertenencia y los de dispositivos parecen simétricos y no lo son, algo que importa si analizas la rapidez con la que surte efecto una revocación.
Revocar un dispositivo sí termina con sus sesiones. El servidor vigila la tabla de dispositivos emparejados y descarta cualquier sesión activa cuyo dispositivo haya salido del conjunto activo, en cuestión de segundos.
Eliminar a un miembro no cierra el socket. WorkspaceMemberRemoved sí se
consume: LocalRpcServer y RemoteRelayHost descartan las suscripciones a
espacios de trabajo que ese usuario tenía enganchadas, y RemoteEventForwarder
invalida su caché de pertenencia para que no se envíen más tramas de ese espacio
de trabajo. Lo que deniega el siguiente RPC sigue siendo la comprobación de
roles, que vuelve a resolver la pertenencia en cada llamada, así que su
siguiente petición se rechaza con «Not a member of this workspace». El efecto es
inmediato para cualquier cosa que intenten hacer; simplemente no se consigue
colgándoles la conexión.
Disparadores de pipeline
Sección titulada «Disparadores de pipeline»Los disparadores de pipeline se suscriben a los eventos de dominio e inician
automáticamente los pipelines que coinciden. PipelineTriggerDispatcher escucha
todo el bus y, a continuación:
- Cortocircuita salvo que el tipo de evento sea uno que sabe convertir en una carga útil
- Busca, en todos los espacios de trabajo, los disparadores habilitados que coinciden con ese tipo de evento
- Filtra cada uno a su propio espacio de trabajo y aplica su filtro de coincidencia de carga útil
- Inicia una ejecución por cada disparador que sobrevive
La restricción importante es el paso 1. El bus transporta 53 tipos de evento; el
selector para añadir un disparador solo inicia una ejecución con estos catorce
(ramas de carga útil de EventPayloadMapper):
ExternalPrDetected, PullRequestPublished, PullRequestStatusChanged,
PrMerged, MessageReceived, TicketAssigned,
TicketCompleted, TicketFailed, TicketCancelled,
BudgetThresholdCrossed, RepoAdded, MeetingRecordingStopped, SkillUpdated
y SpaceDeleted. Ningún otro evento puede iniciar un pipeline.
Cómo ve un cliente todo esto
Sección titulada «Cómo ve un cliente todo esto»RemoteEventForwarder traduce los eventos de la clase de notificaciones a
tramas y las envía por RPC a las sesiones conectadas, donde un mapeador de
tramas las convierte en notificaciones dentro de la aplicación. Un cliente
ligero ve, por tanto, una proyección del flujo de eventos del servidor sin ser
responsable de ninguna ejecución, que es justo la razón de ser de la
separación de cliente ligero.
No obstante, no todas las tramas enviadas son una notificación. El flujo del ciclo de vida de las tareas y la reasignación de tickets se reenvían en vivo para alimentar la interfaz, pero no se registran en el flujo de notificaciones ni muestran ningún aviso.
Ver también
Sección titulada «Ver también»- Pipelines y automatización: qué inicia un disparador
- Tickets y delegación: asignación a un agente frente a un equipo
- Arquitectura: cómo encajan los eventos en la regla de dependencias
- Referencia de eventos de dominio: el catálogo completo y sus suscriptores
- Configurar disparadores de pipeline
- Configurar notificaciones