| Rolling | Blue-green | Canary | |
|---|---|---|---|
| Cómo | Sustituye instancias por tandas | Dos entornos, se conmuta el tráfico | Un % pequeño a la versión nueva |
| Rollback | Gradual | Instantáneo: volver a blue | Afecta solo al canary |
| Coste | Los mismos recursos | El doble durante el despliegue | Los mismos + enrutado |
| Cuándo | El caso por defecto | Cambios grandes, rollback crítico | Cambios arriesgados, A/B |
| No usar si | v1 y v2 son incompatibles | Los recursos están justos | El cambio de esquema es incompatible |
La última fila es la que importa, y las tres celdas dicen lo mismo desde ángulos distintos: ninguna de las tres sirve si las dos versiones no pueden coexistir. Blue-green parece la excepción porque conmuta de golpe — pero la base de datos no conmuta con él, y ahí es donde la estrategia se rompe.
¿Está vivo el proceso?
Si falla: reinicia el contenedor.
Debe comprobar solo que el proceso responde. Se mantiene tonto a propósito.
¿Puede atender tráfico?
Si falla: lo saca del balanceo, sin reiniciarlo.
Aquí sí se comprueban las dependencias: base de datos, caché, carga inicial.
Confundirlos tiene una consecuencia muy concreta y muy fea: si el liveness
comprueba la base de datos, una caída de la base de datos reinicia todas tus instancias. Te
quedas sin base de datos y sin aplicación, y el reinicio en bucle además impide que el
servicio se recupere solo cuando la base vuelve.
app.get('/health', (req, res) => res.json({ status: 'ok' })); // liveness: tonto
app.get('/ready', async (req, res) => { // readiness: comprueba
try {
await db.query('SELECT 1');
await redis.ping();
res.status(200).json({ status: 'ready' });
} catch (e) {
res.status(503).json({ status: 'not ready' });
}
});
Un despliegue rolling apaga instancias que están sirviendo peticiones. Sin un apagado ordenado, esas peticiones se pierden — y en el panel eso aparece como un pico de errores 5xx en cada despliegue que el equipo acaba dando por normal.
SIGTERM.server.close()).En Kubernetes lo acompañan terminationGracePeriodSeconds —cuánto se espera antes de
matar el proceso por las bravas— y un preStop con una espera corta, para dar tiempo al
balanceador a dejar de mandar tráfico antes de que el proceso empiece a cerrarse. Ese
desfase de unos segundos es la causa habitual de que el apagado ordenado esté implementado y aun
así se pierdan peticiones.
Por eso la quinta se ejecuta días o semanas después del resto, cuando ya se sabe que nada la
usa. Y por eso el backfill de la fase 3 va por lotes con una pausa entre ellos: un
UPDATE masivo sobre millones de filas bloquea la tabla justo el rato que se intentaba
evitar.
La regla que ordena todo lo demás:
| Operación | Orden | Por qué |
|---|---|---|
| Añadir columna | Esquema primero | El código nuevo necesita algo que aún no existe |
| Eliminar columna | Código primero | Hay que dejar de usarla antes de quitarla |
| Renombrar | Expand-contract | Es añadir y eliminar a la vez |
SELECT * FROM pg_stat_activity WHERE waiting; para ver bloqueos durante una
migración: ¿existe todavía la columna waiting en esa vista, o fue sustituida hace ya
varias versiones mayores por wait_event_type y wait_event? Si es lo
segundo, la consulta no devuelve un resultado vacío — falla, y falla justo en el momento en que
se está mirando una migración en producción. Y la segunda: el capítulo abre con «ejecutan
ALTER TABLE users RENAME COLUMN en producción y la tabla se bloquea durante 20
minutos». ¿Sobre qué motor? Conviene comprobar si un renombrado de columna no es una operación de
metadatos —casi instantánea, aunque tome un bloqueo exclusivo— en el mismo motor que la guía usa
en todos sus ejemplos. Si lo es, la anécdota que justifica el capítulo entero está describiendo un
problema que ese motor no tiene, y el capítulo sigue siendo útil por otras razones.
Dibuja las cinco fases de un renombrado de columna sobre una tabla tuya y escribe al lado el rollback de cada una. Cuando llegues a la quinta y no puedas escribir nada, ya has entendido la lección.
La única fase irreversible es la última, y por eso es la única que no tiene prisa. Ahora las dos preguntas que decides tú y no el patrón: ¿cuánto tiempo dejarías pasar entre la cuarta y la quinta? ¿Y qué comprobarías antes de ejecutarla — una búsqueda en el código, una consulta de uso real de la columna, ambas?