Pipelines y automatización
Los pipelines son la mitad determinista de Control Center. Un agente decide qué decir; un pipeline decide qué ocurre después, siempre de la misma forma. Un pipeline es un DAG de pasos que pueden despachar agentes, ejecutar scripts, ramificar según una condición, distribuirse en abanico sobre una colección y pasar datos entre pasos — persistente, reanudable y con coste calculado.
Existen por tres motivos: encadenar un proceso repetitivo de varios pasos, coordinar varios agentes en secuencia o en paralelo y reaccionar a algo que ha ocurrido sin que haya una persona presente.
Plantillas y ejecuciones
Sección titulada «Plantillas y ejecuciones»Una plantilla (PipelineDefinition) es el DAG declarativo: pasos, entradas
declaradas y configuración. Vive en la base de datos del propio espacio de
trabajo. Una ejecución (PipelineRun) es una instancia de esa plantilla en
marcha, que lleva una bolsa de estado mutable, totales de coste y de tokens y el
estado de cada paso.
Una plantilla tiene muchas ejecuciones. Las ejecuciones sobreviven a un reinicio: el motor recarga las ejecuciones en curso y las retoma donde se quedaron.
Dos redes de seguridad hacen fallar deliberadamente toda la ejecución en lugar de reanudar un paso, porque reanudarlo sería peor que detenerse:
- Un paso que lleva
suspendedmás tiempo quesuspendedStepTimeout(24 horas de forma predeterminada) está esperando tickets que nunca alcanzarán un estado terminal, así que se marca como fallido para liberar la ejecución. La excepción esextras['awaitApproval'] == true, que es la puerta de aprobación parcial deorchestration.awaitApproval.human.gateno está exento. - Un paso declarado
extras: {'idempotent': false}que estaba en curso cuando se detuvo el servidor puede haber aplicado ya su efecto secundario (una fusión squash, la limpieza de un worktree). Volver a ejecutarlo podría aplicarlo por duplicado, así que el motor lo marca como fallido y te deja a ti el reintento.
El tipo programa; el cuerpo trabaja
Sección titulada «El tipo programa; el cuerpo trabaja»Un paso tiene dos partes ortogonales, y mantenerlas separadas es lo que permite que el motor siga siendo pequeño.
El tipo (StepKind) indica al motor cuándo un paso pasa a ser ejecutable
en relación con sus pasos anteriores: eso es lo único que necesita saber el
planificador. Hay seis: trigger, listen, join, router, forEach y
terminal. El cuerpo (bodyKey) es el trabajo que realiza el paso una vez
programado. Los cuerpos son clausuras registradas por clave al arrancar el
servidor, así que muchos pasos de tipos distintos pueden compartir un mismo
cuerpo: por ejemplo, varios pasos listen que ejecutan todos
conversation.promptAgent.
Como la semántica de planificación vive en seis tipos, el catálogo de comportamientos puede crecer sin que nadie toque el planificador. Consulta Tipos de pasos de pipeline para ver el catálogo completo de tipos, cuerpos y su configuración.
Conviene conocer dos consecuencias del diseño del registro antes de escribir una plantilla a mano:
- Un paso cuyo
bodyKeyno está registrado genera un aviso al cargar la plantilla y después nunca se ejecuta. En tiempo de ejecución nada falla de forma ruidosa. Los pasostriggeryterminalestán exentos de ese aviso: el disparador sigue ejecutando el cuerpopipeline.trigger, que no hace nada, para que se activen los escuchadores posteriores; un pasoterminalno tiene cuerpo y es un centinela para el planificador. - Las claves del mapa
extrasde un nodo deben coincidir exactamente; de lo contrario se ignoran en silencio. Soloextras['spaceId']sitúa el trabajo de un paso de agente en una conversación existente.extras['mode'](chat/plan/review) se lee en el nodo que abre la sala (messaging.createSpace, valor predeterminadoreview): un paso de agente posterior no puede volver a definir los permisos de una conversación a la que se ha unido. Cualquier otra grafía de cualquiera de las dos claves se ignora.
Estado y flujo de datos
Sección titulada «Estado y flujo de datos»Los pasos no se llaman entre sí. Leen y escriben en una bolsa de estado
compartida de la ejecución: un paso lee sus entradas por clave, se ejecuta y
escribe su salida de nuevo bajo su propio outputKey. Un StateReducer fusiona
las escrituras simultáneas cuando ramas paralelas apuntan a la misma clave, y un
TemplateRenderer sustituye los marcadores {{...}} de prompts y scripts a
partir de ese mismo estado.
Por eso un pipeline se puede inspeccionar a posteriori: la bolsa de estado es toda la historia de la ejecución.
Qué inicia una ejecución
Sección titulada «Qué inicia una ejecución»Las filas de PipelineTrigger declaran cuándo se inicia una plantilla
automáticamente. Hay cuatro tipos:
| Disparador | Inicia una ejecución cuando |
|---|---|
| Evento de dominio | Se dispara un evento de dominio coincidente — por ejemplo, PullRequestPublished o TicketAssigned |
| Programación | Vence una expresión cron/de intervalo |
| Manual | Lo ejecutas a mano; la presencia de un disparador manual activo es lo que hace que la plantilla aparezca en el selector de ejecuciones |
| Webhook | Un sistema externo hace POST a /webhooks/<token> en el puerto HTTP del servidor |
Los disparadores de eventos son un conjunto cerrado: el despachador conoce 16
tipos de evento y los ofrece en el selector
(EventPayloadMapper.knownEventTypes), y nada más puede iniciar un pipeline.
Catorce de esos 16 tienen un mapeo de payload. Dos —TicketCreated y
TicketStatusChanged— no lo tienen, así que un disparador sobre cualquiera de
ellos queda activo y nunca se dispara. Consulta
Eventos de dominio para ver la
lista completa.
El token del webhook hace también de secreto HMAC: la cabecera
X-Hub-Signature-256: sha256=<hex> de la petición se verifica contra
HMAC-SHA256(body, token), las entregas no verificadas se rechazan y no se
pueden reproducir, y los duplicados se descartan mediante dedupe_key. Como las
filas de disparador son únicas por (espacio de trabajo, tipo de evento,
plantilla), una plantilla puede tener como máximo un disparador de webhook y un
disparador por cada tipo de evento de dominio.
Las plantillas integradas siembran sus disparadores manuales y de eventos activados; los disparadores programados se siembran desactivados, así que un barrido recurrente siempre es opcional.
Las plantillas que se entregan desactivadas
Sección titulada «Las plantillas que se entregan desactivadas»Trece plantillas de pipeline se siembran en cada espacio de trabajo y ocho de
ellas se entregan desactivadas: external_pr_welcome, cross_review,
ticket_to_pr, pr_triage, pre_merge_gate, release_notes, dep_audit y
pr_digest.
Esta es la parte que sorprende a la gente. Sus disparadores se siembran
activados, pero PipelineEngine.start rechaza una plantilla desactivada y
devuelve null, así que el disparador se lanza al vacío y no aparece ninguna
ejecución. La plantilla, y no el disparador, es el interruptor. Actívala en
Ajustes → Espacio de trabajo → Plantillas de pipeline antes de esperar que
cualquiera de esas ocho haga algo.
Volver a sembrar un espacio de trabajo conserva lo que hayas elegido: tu ajuste
isEnabled y tus filas de disparador existentes sobreviven. Hay exactamente una
excepción deliberada: la programación diaria de pr_merged_cleanup se activa a
la fuerza aunque antes estuviera desactivada, porque es recolección de basura.
Sin ella se acumulan filas de worktree, particiones del grafo de código y copias
en escritura, y eso nunca pretendió ser una decisión del usuario.
Otra asimetría que conviene conocer: la plantilla integrada pr_review ya no
publica deliberadamente en GitHub. Publicar una revisión es un paso aparte que
requiere la aprobación del usuario, y un pipeline que publicara directamente lo
haría por duplicado. cross_review, ticket_to_pr y pr_triage sí siguen
publicando un comentario directamente en GitHub cuando se ejecutan.
Qué sabe el motor
Sección titulada «Qué sabe el motor»PipelineEngine crea el registro de la ejecución, programa el nodo de inicio
que corresponde al tipo de evento de la ejecución y luego recorre el DAG: a
medida que los pasos se completan, evalúa los disparadores posteriores, resuelve
las ramas del enrutador, espera en los puntos de unión, aplica las políticas de
reintento y de continuar en caso de fallo, y persiste el estado, el coste y los
errores en cada paso. Las aristas que salen de otro inicio se ignoran para esa
ejecución, así que un disparo por programación no espera a una condición
exclusiva de la ejecución manual.
Lo que no sabe es nada sobre tickets, despacho, GitHub o mensajería. Su único
punto de extensión es PipelineBodyRegistry. Los cuerpos registrados allí son
los que contienen AgentDispatchPort, MessagingPort y sus hermanos; por eso
añadir una capacidad a los pipelines nunca implica cambiar el planificador.
Gestión de errores
Sección titulada «Gestión de errores»Un paso que falla registra su mensaje de error y pasa a failed. Si el paso
declara continueOnFail, los pasos posteriores continúan y el error se guarda
en el estado de la ejecución; de lo contrario, la ejecución falla. Un paso con
una StepRetryPolicy se reintenta primero, con retroceso lineal o exponencial,
antes de que se aplique cualquiera de las dos opciones anteriores.
Consulta también
Sección titulada «Consulta también»- Eventos de dominio: a qué escucha un disparador de eventos
- Orquestación: un plan que apruebas y que se compila en uno de estos pipelines
- Tickets y delegación: lo que crean y completan los pasos de pipeline
- Tipos de pasos de pipeline: el catálogo completo de tipos, cuerpos y configuración
- Crea tu primer pipeline
- Crear una plantilla de pipeline
- Ejecutar un pipeline manualmente
- Supervisar ejecuciones de pipeline
- Configurar disparadores de pipeline