8 min de lectura

Endpoints de rollback para despliegues autónomos sin colisiones

Diseña endpoints de rollback para despliegues autónomos que restauren la versión correcta, rechacen estados obsoletos y conserven los cambios de producción que no estén relacionados.

Endpoints de rollback para despliegues autónomos sin colisiones

Los agentes de despliegue autónomos necesitan permiso para fallar de forma segura, no permiso para adivinar. El rollback peligroso rara vez es un comando que falla. Es un comando que tiene éxito después de que el entorno haya cambiado y restaura un artefacto antiguo sobre una versión que el agente no creó.

Una acción de rollback segura identifica un intento de despliegue concreto, nombra una versión anterior concreta y se niega a actuar cuando su visión del estado actual ha quedado obsoleta. Trata el rollback como una transición de estado protegida, no como un atajo hacia «la última versión buena». Esa diferencia determina si un agente repara su propio trabajo o borra el de otra persona.

Un rollback debe pertenecer a un único intento de despliegue

Los endpoints de rollback deben vincular la reversión con el intento de despliegue que provocó el fallo sospechado. Un número de versión no basta para hacerlo.

Los equipos suelen guardar una secuencia como 1.8.4, 1.8.5 y 1.8.6, y después exponen una operación que dice «despliega 1.8.4 en producción». Un agente despliega 1.8.5, recibe una alerta y llama a esa operación. Mientras tanto, un ingeniero ha desplegado la versión urgente 1.8.6. El endpoint de rollback acepta la solicitud porque 1.8.4 existe. Ahora producción ejecuta un artefacto anterior a ambos cambios. La API hizo exactamente lo que se le pidió, y ese es el problema.

Mantén separadas estas identidades:

  • Una versión es un paquete inmutable de código, referencias de configuración y metadatos. Asígnale un ID duradero y un digest del artefacto.
  • Un intento de despliegue es una solicitud para poner una versión en un objetivo con nombre. Tiene un ID de despliegue, un actor y un ciclo de vida.
  • El estado del objetivo es lo que el entorno ejecuta en ese momento. Incluye una revisión o generación que cambia con cada transición aceptada.
  • La intención de rollback indica que el intento de despliegue D puede restaurar la versión R del objetivo solo si D sigue siendo el propietario del estado actual.

El campo que suele omitirse es el vínculo de propiedad. Cuando el despliegue dep_842 promociona la versión rel_105, registra que dep_842 creó la generación actual del objetivo gen_913. Un rollback vinculado a dep_842 solo puede continuar mientras gen_913 siga siendo la actual. Si un despliegue posterior crea gen_914, el servicio debe rechazar la solicitud antigua.

No infieras la propiedad comparando marcas de tiempo. El orden de los relojes falla con los reintentos, los trabajadores en cola, las reparaciones manuales y cualquier sistema que permita a un usuario seleccionar una versión anterior. Guarda la relación directa cuando aceptes la promoción.

Esto también responde a una pregunta operativa incómoda: ¿puede un agente revertir el despliegue de otro agente? Normalmente, no. Una autoridad independiente puede autorizar explícitamente esa intervención, pero la capacidad normal de rollback debería cubrir solo las acciones iniciadas por quien llama. La autoridad amplia parece cómoda hasta que dos ciclos de despliegue reaccionan ante el mismo incidente.

La procedencia inmutable permite conocer la versión anterior

El servicio debe capturar la procedencia del rollback antes de cambiar el objetivo, porque después de una promoción la palabra «anterior» se vuelve ambigua. Consultar el historial de versiones después de una alerta es una receta para seleccionar lo que casualmente estaba junto a otra entrada en una lista.

Cuando un servicio de despliegue acepta una promoción, debe crear un registro que incluya la versión estable anterior elegida en ese momento. Esa versión puede diferir del evento inmediatamente anterior. Por ejemplo, un canary puede promocionar rel_105 después de que rel_103 siga siendo la base estable, mientras rel_104 fue un experimento cancelado. El objetivo correcto de recuperación puede ser rel_103, no la fila situada justo antes de rel_105.

Un registro mínimo podría ser así:

{
  "deployment_id": "dep_842",
  "environment": "production",
  "release_id": "rel_105",
  "artifact_digest": "sha256:8b2c...",
  "source_revision": "4f1d9c7",
  "config_digest": "sha256:1a06...",
  "prior_release_id": "rel_103",
  "created_target_generation": "gen_913",
  "migration_set_id": "mig_77",
  "actor_id": "agent-run-27"
}

prior_release_id es una decisión, no un campo de conveniencia. Tu controlador de promociones debe elegirlo con reglas que los operadores puedan inspeccionar: la última versión estable verificada para ese objetivo, quizá con configuración y requisitos de migración compatibles. La operación de rollback consume esa decisión guardada. No la recalcula porque la tabla del historial haya cambiado.

La identidad del artefacto necesita algo más que una etiqueta de versión legible. Las etiquetas pueden cambiar de destino. Las etiquetas de compilación pueden reutilizarse por accidente. Un rollback debe desplegar la referencia inmutable del artefacto, basada en su contenido o equivalente, registrada en el intento original. Si tu registro permite que una etiqueta apunte a bytes diferentes más adelante, el ID de la versión debe resolverse al digest capturado en el momento de la promoción.

La configuración merece la misma disciplina. Revertir los bytes de la aplicación y dejar una bandera de funcionalidad modificada, una referencia a un secreto de ejecución, una política de descarga de imágenes o un ajuste de recursos puede crear un sistema que nunca existió en las pruebas. No tienes que duplicar todos los valores en el registro del despliegue, pero sí registrar una revisión o un digest de configuración inmutable y definir si el rollback la restaura.

El estado de la base de datos marca un límite independiente. Una versión que solo añade columnas que aceptan valores nulos suele permitir revertir la aplicación. Una versión que elimina una columna, reescribe valores o cambia significados puede no permitirlo. No prometas un «rollback completo» genérico si el planificador de versiones no puede demostrar la compatibilidad. Marca el despliegue como reversible a nivel de aplicación, reversible a nivel de tráfico o necesitado de reparación. Una negativa resulta menos embarazosa que ejecutar código antiguo contra un esquema que no puede entender.

El endpoint necesita la versión actual esperada

Una solicitud de rollback debe llevar tanto la versión que quiere restaurar como el estado activo que espera reemplazar. Sin esa condición previa, el endpoint no puede distinguir una recuperación válida de una instrucción obsoleta.

Usa un contrato de solicitud como este:

POST /v1/environments/production/rollbacks
Idempotency-Key: 7e4cd1ee-62cb-4efa-985f-4ee0b77d577b
Content-Type: application/json

{
  "origin_deployment_id": "dep_842",
  "expected_current_release_id": "rel_105",
  "expected_target_generation": "gen_913",
  "restore_release_id": "rel_103",
  "reason": "error rate exceeded release threshold",
  "approval_id": "apr_551"
}

El servicio debe obtener restore_release_id de origin_deployment_id cuando sea posible y después comparar el valor enviado con prior_release_id. Mantener ambos campos en la solicitud ayuda a los auditores a ver la intención declarada por el agente, pero prevalece el registro del servidor. Nunca permitas que quien llama convierta su propio despliegue en una licencia para elegir cualquier artefacto histórico.

Cuando tenga éxito, devuelve el nuevo intento de despliegue y la nueva generación del objetivo. No devuelvas una respuesta vaga de accepted si el sistema puede reservar la transición de forma síncrona.

{
  "rollback_deployment_id": "dep_849",
  "reverted_deployment_id": "dep_842",
  "previous_release_id": "rel_105",
  "current_release_id": "rel_103",
  "target_generation": "gen_914",
  "status": "running"
}

Si el objetivo activo ya no coincide, devuelve una respuesta de conflicto. El cuerpo debe incluir información suficiente para que un agente informe de lo ocurrido, pero no tanta autoridad como para improvisar una acción nueva.

HTTP/1.1 409 Conflict
Content-Type: application/json

{
  "error": "stale_rollback",
  "origin_deployment_id": "dep_842",
  "expected_target_generation": "gen_913",
  "observed_target_generation": "gen_914",
  "observed_release_id": "rel_106"
}

Un 409 es un resultado de seguridad exitoso. Enseña al agente que debe detenerse ante este resultado, adjuntar la respuesta a su registro del incidente y solicitar una decisión nueva. No le des una instrucción alternativa como «intenta de nuevo sin la generación esperada». Esa alternativa convierte tu protección en una representación.

Algunos equipos usan un encabezado HTTP If-Match con un ETag en lugar de un campo JSON. Funciona si el ETag representa el estado del objetivo y cambia en cada transición. El mecanismo importa menos que la invariante: el comando debe nombrar el estado que puede reemplazar.

La serialización evita que dos solicitudes válidas colisionen

Una comprobación de condición previa por sí sola no puede proteger un objetivo si dos trabajadores pueden superarla antes de que cualquiera confirme el cambio. El servicio de despliegue debe serializar los cambios del mismo entorno y usar una operación atómica de comparación e intercambio en el almacén de estados.

Supón que el objetivo actual es (rel_105, gen_913). Un agente envía un rollback y un operador envía rel_106. Ambas solicitudes leen gen_913. Si el servicio comprueba el estado en la memoria de la aplicación y después escribe sin condiciones, ambas llamadas pueden declarar éxito. La última escritura gana y tu registro de auditoría informa de un estado que quizá nunca existió para los usuarios.

Pon la comparación y la mutación en una sola transacción o en una escritura condicional. Una implementación relacional podría usar este patrón:

UPDATE environment_targets
SET release_id = :restore_release_id,
    generation = generation + 1,
    active_deployment_id = :rollback_deployment_id,
    updated_at = CURRENT_TIMESTAMP
WHERE environment = :environment
  AND generation = :expected_generation
  AND release_id = :expected_release_id;

El servicio comprueba el número de filas afectadas. Una fila modificada reserva la transición de estado. Cero filas significa conflicto. Después debe leer el objetivo actual y devolver los valores observados en la respuesta 409.

Una cola no sustituye esta condición. Las colas reducen la probabilidad de trabajo simultáneo, pero la entrega duplicada, una ruta manual fuera de la cola o un reintento del trabajador todavía pueden producir comandos enfrentados. Mantén la escritura condicional donde vive el estado.

La idempotencia resuelve otro fallo. Un agente puede perder la respuesta después de que el servicio acepte el rollback. Si reintenta con la misma clave de idempotencia, el servicio debe devolver el despliegue de rollback y el estado originales. No debe reservar otra generación ni iniciar una segunda ejecución.

Limita la idempotencia al autor y al endpoint, registra un digest del cuerpo de la solicitud y rechaza una clave reutilizada con un cuerpo diferente. De lo contrario, un cliente defectuoso puede asociar una intención nueva con una solicitud anterior al reutilizar un identificador.

Un rollback puede conservar un estado defectuoso de las dependencias

Detén las acciones desde la bóveda
Cuando la bóveda está bloqueada, Sallyport rechaza todas las acciones HTTP y SSH.

El rollback de una aplicación y la recuperación del entorno son operaciones distintas. Un endpoint que despliega código antiguo no puede hacer automáticamente compatibles de nuevo todas las dependencias.

He visto la versión predecible de este fallo: la versión rel_105 introdujo código que escribe un nuevo valor de enumeración. Después, una migración endureció una restricción de la base de datos para permitir solo los valores nuevos. La versión falló por un motivo no relacionado y el operador restauró rel_103. El código antiguo escribió el valor anterior, la base de datos lo rechazó y el incidente creció porque el rollback parecía completo en el panel de despliegues.

El endpoint no provocó el cambio de esquema, pero su respuesta de éxito hizo una afirmación falsa. Evita esa afirmación exigiendo metadatos de la versión que describan la compatibilidad en términos concretos. Como mínimo, registra si la versión restaurada puede leer los datos actuales, escribir datos actuales y funcionar con la revisión de configuración del objetivo.

La gestión del tráfico tiene su propia trampa. Un rollback de canary normalmente debería cambiar solo la distribución de tráfico que ese canary controla. Si una versión independiente ha ajustado el grupo estable o si otro controlador ha cambiado una regla de enrutamiento, un endpoint de rollback que escriba un documento de enrutamiento completo puede borrar esos cambios. Usa versiones a nivel de recurso o aplica parches solo a los campos de distribución que el despliegue reservó.

El mismo principio se aplica a la infraestructura. Si una versión creó una cola, un bucket, un rol o una regla de firewall que un trabajo posterior adoptó, eliminarlo durante la reversión puede perjudicar a otro servicio. La limpieza requiere un registro de propiedad del recurso y una comprobación de que ningún despliegue posterior lo haya reclamado. Si no puedes demostrar esa propiedad, deja el recurso en su sitio y crea una tarea de reparación.

Para las operaciones irreversibles, elige una reparación posterior. El agente puede desactivar una bandera de funcionalidad, desviar el tráfico o desplegar una versión correctiva. A los operadores no les gusta esa respuesta porque «rollback» parece más rápido, pero una reversión impecable que destruye datos posteriores cuesta más tiempo que un plan de reparación.

Los agentes necesitan autoridad limitada y un punto de detención visible

Un agente autónomo debe recibir la autoridad mínima necesaria para completar el despliegue que tiene asignado. No necesita credenciales de nube sin restricciones, un shell general con acceso a producción ni un endpoint que acepte IDs de versión arbitrarios.

Entrega al agente un identificador de despliegue cuando empiece una versión. Ese identificador puede autorizar lecturas de estado, comprobaciones de salud, cambios de tráfico dentro de la distribución del despliegue y un rollback que nombre el despliegue original. Haz que caduque cuando el despliegue alcance un estado terminal o cuando una persona revoque la ejecución. El servicio de despliegue debe aplicar aun así la propiedad en el servidor, porque un identificador puede copiarse o un cliente puede funcionar mal.

La aprobación humana debe producirse antes del límite irreversible, no después de que el agente haya preparado un comando irreversible. Una política razonable solicita aprobación cuando un agente inicia un despliegue en producción y después le permite revertir exactamente ese despliegue mientras se mantenga la condición de propiedad. Si el agente encuentra una versión posterior, necesita una aprobación nueva para cualquier intervención. Es un buen momento para detenerse porque alguien cambió la situación.

Sallyport puede mantener las credenciales HTTP y SSH fuera del proceso del agente mientras una persona aprueba la ejecución del agente o marca una credencial para solicitar aprobación en cada uso. Ese control ayuda a proteger el flujo de acciones, pero el servicio de rollback todavía necesita sus propias comprobaciones de versión y generación. La custodia de credenciales no puede definir la propiedad del despliegue.

Evita nombres de capacidades como production:rollback:any. Invitan a quien llama a elegir el alcance durante la ejecución. Prefiere una capacidad emitida por el servidor y vinculada a dep_842, al entorno production y a la ruta de rollback específica. Si el agente solicita un objetivo no relacionado, la capa de autorización debe rechazarlo antes de que el controlador de despliegue evalúe la solicitud.

Registra la identidad del proceso o de la carga de trabajo del agente en cada solicitud. Una persona debe poder responder quién inició dep_842, qué código firmó o autenticó a quien llamó, qué aprobación lo cubría y si alguien revocó el acceso antes de que terminara la ejecución. Las cuentas de automatización anónimas convierten cada incidente en un trabajo de arqueología.

La verificación debe probar la versión restaurada, no la solicitud

Protege las credenciales de rollback
Sallyport ejecuta llamadas a la API de rollback mientras las credenciales de producción permanecen cifradas en su bóveda.

Un rollback solo termina cuando el objetivo ejecuta la versión prevista y el servicio verifica las condiciones que justificaron la recuperación. HTTP 202, una salida de comando exitosa o un evento del controlador que diga «aplicado» no demuestra que la versión antigua atienda el tráfico correctamente.

Define la verificación según el modo de fallo real del despliegue. Si la latencia o los errores activaron el rollback, observa el servicio restaurado mediante el mismo recorrido de medición después de que reciba tráfico. Si una versión de trabajadores consumía trabajos malformados, verifica la versión del trabajador y una carga controlada. Si un error de configuración provocaba fallos de arranque, inspecciona las instancias listas y la revisión de configuración que cargaron.

Mantén una ventana de observación limitada y registra su resultado. El endpoint puede informar verifying, después succeeded, failed o needs_operator. No esperes indefinidamente una métrica que quizá no esté disponible. Un límite de tiempo debe producir un resultado explícito de inconcluso, seguido de una decisión del operador.

El evento de auditoría debe conectar todas las etapas: la alerta o regla que solicitó la reversión, el despliegue de origen, el estado esperado, la reserva condicional, los eventos de ejecución, las pruebas de salud, el estado final y cualquier revocación. Los eventos necesitan controles de orden e integridad porque una cronología de despliegue amigable no basta durante una disputa.

Sallyport registra las ejecuciones de agentes y las acciones individuales en un registro de auditoría cifrado y encadenado mediante hashes, y sp audit verify comprueba esa cadena sin conexión y sin una clave de la bóveda. Usa ese tipo de prueba para demostrar que un agente solicitó una acción, pero conserva el registro propio de transición de estado y verificación del servicio de despliegue como la fuente autorizada de lo que cambió.

Los comandos de rollback conocidos necesitan una capa más segura

Protege el endpoint de rollback
Inyecta credenciales bearer, básicas o de encabezado personalizado en la llamada HTTP protegida de rollback.

kubectl rollout undo resulta útil para un operador que trabaja directamente con un Deployment de Kubernetes, pero no constituye un contrato completo para la recuperación autónoma. Kubernetes documenta que kubectl rollout undo revierte a la revisión anterior del despliegue, a menos que quien llama proporcione --to-revision. Ese valor predeterminado tiene sentido durante un diagnóstico práctico. No demuestra que la revisión anterior pertenezca a la ejecución fallida del agente.

Un Deployment de Kubernetes registra el historial de revisiones en ReplicaSets, mientras que revisionHistoryLimit controla cuánto historial conserva Kubernetes. Ese historial es un artefacto del controlador, no tu registro empresarial de la base aprobada de una versión, su compatibilidad de configuración o la propiedad del agente. Cuando se elimina parte del historial, «undo» también puede no encontrar la revisión que espera un proceso de despliegue externo.

No entregues a un agente una credencial general de kubectl y llames a ese comando tu endpoint de rollback. Coloca un controlador o servicio de despliegue entre el agente y el clúster. El servicio debe resolver el registro del despliegue de origen, comparar la generación activa del objetivo, reservar el cambio de estado e invocar la plataforma subyacente solo después de superar esas comprobaciones.

La misma crítica se aplica a los comandos de proveedores de nube que dicen «despliega la revisión X» o a los controles de CI que dicen «vuelve a ejecutar la versión anterior». Operan sobre un recurso de la plataforma. No saben si una versión está relacionada con el incidente actual del agente a menos que tu plano de control les proporcione ese contexto.

Mantén también limitado el comando de la plataforma. Si el servicio puede aplicar un parche a una revisión de una carga de trabajo identificada, evita concederle permisos de mutación en todo el clúster. Un wrapper que conserve credenciales amplias solo ha ocultado el peligro detrás de otra API.

Crea un registro de versiones antes de automatizar la recuperación

Puedes introducir un rollback protegido sin sustituir todos los sistemas de despliegue. Empieza por hacer que el registro de versiones sea la fuente autorizada para un objetivo de producción y después obliga a que las rutas humanas y de los agentes pasen por la misma transición condicional.

Una secuencia práctica de implantación tiene cinco partes:

  1. Asigna IDs inmutables a las versiones y a los intentos de despliegue, y registra la versión aprobada anterior y la generación del objetivo en el momento de la promoción.
  2. Añade un endpoint que requiera origin_deployment_id, la versión esperada, la generación esperada y una clave de idempotencia.
  3. Haz que la actualización del objetivo sea condicional en la base de datos o en el almacén de control, y devuelve 409 ante cualquier discrepancia.
  4. Clasifica cada versión según la reversibilidad de la aplicación, la configuración, los datos y el tráfico antes de promocionarla.
  5. Exige pruebas de verificación antes de que el controlador marque un rollback como completado.

Ejecuta este contrato en modo de informe antes de permitir que los agentes lo ejecuten. Deja que el servicio calcule qué restauraría y si rechazaría la solicitud. Compara esas decisiones con las acciones reales de los incidentes. Así descubrirás registros de procedencia incompletos y rutas manuales ocultas sin dar a la automatización la posibilidad de sobrescribir producción.

Después haz que el rechazo sea algo normal. Un rollback obsoleto debe crear un elemento de incidente comprensible con la versión y la generación observadas, no un fallo misterioso que anime a alguien a evitar el endpoint. El endpoint gana confianza cuando rechaza de forma constante una solicitud insegura, incluidas las solicitudes de las personas que lo construyeron.

El primer campo que debes añadir no es force. Es expected_target_generation. Cuando tus despliegues transporten ese dato y conserven la base original, un agente podrá revertir su propia versión con un límite claro. Hasta entonces, el rollback autónomo no es más que un comando de despliegue antiguo apuntando a un objetivo que se mueve.

FAQ

¿Qué debe restaurar un rollback de despliegue?

Un rollback de despliegue debe identificar un artefacto anterior y la instancia exacta del despliegue que lo introdujo. «Versión anterior» por sí sola es demasiado imprecisa porque otra versión puede haber cambiado el objetivo después de que el agente empezara a trabajar.

¿Cómo evito que un rollback sobrescriba un despliegue más reciente?

Usa una condición de comparación e intercambio, como expected_current_release_id. El servicio debe rechazar la solicitud cuando la versión activa sea distinta, porque continuar sobrescribiría el despliegue posterior de otra persona.

¿Es seguro permitir que un agente de IA llame a una API de rollback?

Solo cuando el objetivo tenga un único escritor autorizado, las revisiones sean inmutables y el endpoint compruebe la revisión actual antes de cambiar nada. Un endpoint simple que acepta un entorno y una versión no puede ofrecer esa garantía.

¿Qué datos debo guardar para admitir rollbacks seguros?

Conserva un catálogo inmutable de versiones con el digest del artefacto, la revisión de origen, el digest de configuración, el conjunto de migraciones, el ID del despliegue, el actor y las marcas de tiempo. Guarda el ID real de la versión anterior en lugar de pedir al servicio de rollback que infiera el historial al recibir la solicitud.

¿Debe un rollback revertir las migraciones de la base de datos?

No. Un rollback puede restaurar el código de la aplicación, las proporciones de tráfico o un valor de configuración, pero los cambios destructivos del esquema suelen requerir una reparación posterior independiente. Trata la compatibilidad de la base de datos como una propiedad de la versión, no como un efecto automático del rollback de una aplicación.

¿Qué debe hacer un agente después de un conflicto de rollback?

Debe devolver un resultado de conflicto explícito, como HTTP 409, con el ID de la versión actual observada y la condición solicitada. El agente debe detenerse, informar del conflicto y esperar a que una persona autorizada o un plan de despliegue nuevo tome una decisión.

¿Puedo usar kubectl rollout undo para un rollback autónomo?

kubectl rollout undo puede ser útil para que un operador investigue un Deployment concreto, pero su comportamiento predeterminado de usar la revisión anterior no vincula la solicitud con la versión que el agente pretende revertir. Coloca un servicio de despliegue delante de ese comando y aplica allí las comprobaciones de propiedad y revisión.

¿Cómo deben gestionar los reintentos las solicitudes de rollback?

Usa una única clave de idempotencia para una intención de rollback y guarda el resultado final asociado a ella. Si el agente reintenta después de un tiempo de espera, el servicio debe devolver el resultado anterior en lugar de iniciar otro despliegue gradual.

¿Qué debe contener el registro de auditoría de un despliegue autónomo?

Registra la solicitud, la identidad del actor, los IDs de versión esperados y observados, el objetivo seleccionado, la aprobación, los eventos de ejecución y el resultado de la verificación. Conserva pruebas suficientes para explicar tanto un cambio exitoso como una negativa a cambiar nada.

¿Qué campos pertenecen a un endpoint de rollback?

Un endpoint útil incluye la versión actual esperada, una versión anterior identificada, el motivo, una clave de idempotencia y una referencia de aprobación. Si una API no puede aceptar esos campos, mantenla detrás de un controlador que sí pueda hacerlo.

Sallyport

Sallyport ejecuta llamadas de API y comandos SSH por tu agente de IA. Las claves se quedan en una bóveda local de tu Mac; tú apruebas cada ejecución y cada acción queda en un registro sellado.

© 2026 Sallyport · Código abierto bajo Apache-2.0 · Oleg Sotnikov