Le pides a un amigo que pague la cuenta de la luz por internet. Te escribe "ya lo hago" y justo se le apaga el teléfono. ¿Se hizo el pago? Si pagas tú, quizá pagues dos veces; si no, quizá te corten la luz. Nadie hizo nada mal; simplemente no hay forma de saber qué pasó.
Un vive en esa situación. Una ejecución puede durar veinte minutos copiando un repositorio, editando archivos, corriendo tests y guardando commits, y mientras tanto la laptop puede suspenderse, la red puede caerse o el proceso puede morir. La pregunta difícil no es "¿cómo lo intento de nuevo?", sino "¿ya ocurrió?". Un reintento a ciegas puede subir un cambio dos veces; no reintentar puede perder trabajo en silencio.
Lograr que el trabajo sobreviva a caídas así se llama (durable execution). Esta lección cubre cuatro ideas: por qué la necesitan las ejecuciones de , cómo mantener un solo dueño por ejecución, qué hacer cuando el resultado es desconocido y cómo demostrar que el diseño funciona. El caso de estudio es la flota de de Tack, las máquinas que ejecutan sus agentes.
Por qué una ejecución de agente es distinta
Una petición corta a un servidor web casi siempre se puede reintentar sin pensarlo mucho. Una ejecución de agente, no. Dura minutos u horas, así que fallar a mitad de camino no es raro. Cambia cosas fuera del sistema, y reiniciar no deshace un commit ni un deploy. Y la historia de lo que pasó queda repartida entre varias máquinas.
Los reintentos y timeouts en general se tratan en Observabilidad, auditoría y confiabilidad. Esta lección trata de quién es dueño del trabajo.
Trabajadores que piden trabajo
El servidor central puede llamar a las máquinas que hacen el trabajo, o cada trabajador puede preguntar "¿hay algo para mí?" y luego reportar. El segundo estilo es un modelo pull, el mismo que usan los runners de GitHub Actions. Los trabajadores solo hacen conexiones de salida, así que pueden estar detrás de un firewall; el servidor nunca necesita claves para entrar en ninguna máquina; y un trabajador caído simplemente deja de preguntar.
En Tack
- Tablerouno solo
- Elige el próximo trabajo
- Guarda el historial de cada ejecución
- No ejecuta código ni tiene claves
- Runnermuchos, al lado del código
- Pide trabajo
- Arranca el agente de código
- Conserva la clave del proveedor
Un solo dueño a la vez: leases y fencing tokens
Piensa en un cartel de "reservado" en la mesa de un restaurante que solo vale hasta las 8 de la noche. Si el cliente no llega, la mesa no queda bloqueada toda la noche. En software, ese cartel es un : un derecho sobre un trabajo que vence solo. El trabajador que lo tiene lo mantiene vivo reportándose con regularidad, con mensajes breves llamados heartbeats (latidos). Si se detienen, el lease vence y otro trabajador puede tomar el relevo.
El vencimiento crea un problema nuevo. El trabajador A se congela un rato, su lease vence y el trabajador B toma el trabajo. Luego A despierta, sin enterarse de nada, e intenta guardar sus resultados. Ahora dos trabajadores creen ser dueños de la misma ejecución.
La solución funciona como los números de turno en el mostrador de una panadería. Cada vez que se entrega el trabajo, recibe un número uno más alto que antes: A tenía el 33, B tiene el 34. Cada escritura debe mostrar su número y el registro solo acepta el vigente, así que el 33 de A se rechaza. Ese número es un . Un trabajador congelado puede seguir vivo, pero ya no puede modificar el registro.
- Turno 33el trabajador A tiene el lease
- A se congelacesan los heartbeats, el lease vence
- Turno 34el trabajador B toma el relevo
- A intenta guardarmuestra el 33 y se rechaza
- B sigueel único dueño válido
Cuando nadie sabe qué pasó: detenerse, no adivinar
Vuelve al amigo con el teléfono apagado: lo sensato es verificar antes de pagar otra vez, y preguntar si no puedes verificar. Cuando un runner se cae después de iniciar un agente, el servidor no puede probar si el agente sigue corriendo ni qué cambió. La regla tentadora es "el lease venció, lo inicio de nuevo". Tack hace lo contrario.
Dos hábitos lo hacen seguro. El runner anota lo que va a hacer antes de hacerlo, en un registro local llamado journal, así que tras reiniciarse puede informar lo que sabe. Y cada mensaje es idempotente: enviarlo dos veces tiene el mismo efecto que enviarlo una, así que un reporte repetido no hace daño.
En Tack
- Caídamuere el runner o su máquina
- Reinicioel runner lee su journal
- Reportedetenido, corriendo o dudoso
- Decisión
- Nunca arrancóse reintenta solo
- Cualquier otro casouna persona decide y da una razón
El costo es que a veces una persona tiene que intervenir. Para agentes cuyos cambios cuesta revertir, ese costo suele valer la pena.
Demostrarlo: matar al trabajador a mitad de camino
Un diseño así vale lo que valen sus pruebas. La honesta es directa: iniciar una ejecución real, matar al trabajador en plena tarea y verificar que la ejecución no se pierde, que no arranca un duplicado y que el reintento termina bien una vez que alguien decide.
En la práctica
- Enumera los efectos que no se pueden repetir sin daño, como pushes, deploys, pagos y correos. Ahí necesitas o una decisión humana.
- Compara construir con adoptar. Un motor como Temporal da garantías fuertes a cambio de más infraestructura y una forma más rígida de programar. Un diseño propio más acotado cuesta menos de operar, pero exige pruebas de caída serias.
- Deja las claves donde corre el trabajo. Un modelo pull permite que las credenciales se queden en la máquina que ejecuta.
Para profundizar
La documentación de Tack trata sus runners con más detalle que esta lección (en inglés):
- Introduction explica por qué Tack separa el tablero del runner y cómo cada uno sobrevive a la falla del otro.
- Agent Runners & Fleet Execution es la guía de operación: cómo registrar runners, dónde viven las claves y los espacios de trabajo, y qué partes están probadas de punta a punta hoy.
- Recovery Runbook recorre una caída paso a paso: qué reporta el runner, cómo decide el servidor y cómo una persona resuelve un caso dudoso.
Para llevar
- Ningún efecto externo tiene garantizado ocurrir exactamente una vez; apunta a un solo dueño válido a la vez más acciones seguras de repetir.
- Un lease evita que el trabajo quede bloqueado para siempre; un fencing token evita que un dueño anterior sobrescriba al nuevo.
- El fencing protege tu registro, no el mundo, así que los resultados desconocidos necesitan una regla explícita.
- Cuando un efecto no se puede revertir, detenerse y consultar a una persona es mejor que reintentar a ciegas.
- Un diseño durable solo es creíble si una prueba mata al trabajador a mitad de camino.
Comprueba lo aprendido
Un lease ya vence solo. ¿Para qué agregar un fencing token?
El dueño anterior puede volver sin saber que perdió el lease e intentar escribir. El fencing token permite que el registro rechace esa escritura obsoleta.
Un runner se cayó después de iniciar un agente. ¿Por qué no iniciarlo de nuevo sin más?
Nadie sabe si el primer agente sigue corriendo ni qué cambió, así que iniciarlo otra vez podría repetir un push o un deploy. Solo es seguro reintentar cuando hay certeza de que nada arrancó; si no, decide una persona.
¿Por qué ayuda que los trabajadores pidan trabajo en lugar de que los llamen?
El servidor nunca se conecta a las máquinas de los trabajadores ni guarda sus claves, y un trabajador caído simplemente deja de preguntar.