Saltar al contenido

Cómo hacer deploys sin downtime: lo que aprendimos en producción

CS
Chakana Studio Software
· · 8 min de lectura

El deploy a producción debería ser aburrido. Un evento rutinario, sin drama, sin “cerramos por mantenimiento”, sin usuarios que pierden lo que estaban haciendo.

Llegar a ese punto requiere pensar la arquitectura correctamente desde el inicio. Aquí están las estrategias que usamos y cuándo aplica cada una.

El problema con los deploys “ingenuos”

Un deploy típico sin ninguna estrategia especial:

  1. Detener el servidor actual
  2. Reemplazar el código
  3. Iniciar el nuevo servidor

Durante los pasos 1 a 3, la aplicación no responde. Si el inicio tarda 30 segundos, tienes 30 segundos de downtime. Si algo falla en el inicio, el downtime se extiende hasta que alguien lo detecta y actúa.

Para una aplicación interna usada en horario de oficina, esto puede ser aceptable. Para un e-commerce, una plataforma SaaS o cualquier sistema con usuarios activos las 24 horas, no lo es.

Blue-Green deployment: la estrategia más confiable

La idea: mantener dos entornos de producción idénticos (azul y verde). En cualquier momento, uno está activo y el otro está en espera.

Cómo funciona:

  1. El entorno azul está sirviendo el tráfico actual
  2. Desplegamos la nueva versión en el entorno verde (que no recibe tráfico)
  3. Verificamos que el verde funciona correctamente
  4. Redirigimos el tráfico al verde (cambio instantáneo en el load balancer)
  5. El azul queda en espera — si hay un problema, revertir es volver a apuntar al azul

Ventaja principal: el rollback es inmediato. Si la nueva versión tiene un bug crítico, volver a la versión anterior toma segundos, no minutos.

Desventaja: necesitas el doble de infraestructura corriendo simultáneamente durante el deploy.

Rolling deployment: para la mayoría de casos

Si tienes múltiples instancias de tu aplicación (horizontal scaling), el rolling deployment actualiza una instancia a la vez mientras las otras siguen sirviendo tráfico.

Cómo funciona:

  1. Tienes 4 instancias corriendo la versión A
  2. Detenes la instancia 1, la actualizas a versión B, la vuelves a iniciar
  3. El load balancer solo envía tráfico a las instancias saludables
  4. Repites para las instancias 2, 3 y 4

Ventaja: no necesitas infraestructura extra. Simple de implementar con orquestadores modernos (Kubernetes, Railway, ECS).

Consideración importante: durante el rolling update, coexisten la versión A y la versión B. Si hiciste un cambio de base de datos incompatible hacia atrás, esto puede generar errores. Las migraciones tienen que ser backwards-compatible.

Migraciones de base de datos: el problema más subestimado

La parte más delicada de los deploys sin downtime es la base de datos. Cambiar una columna de nombre, eliminar una tabla, cambiar un tipo de dato — estas operaciones pueden romper la versión anterior si se ejecutan antes de que todos los servidores estén en la nueva versión.

La regla: las migraciones de base de datos tienen que ser backwards-compatible con la versión anterior del código por al menos un ciclo de deploy.

Patrón para renombrar una columna sin downtime:

  1. Deploy 1: agrega la columna nueva, el código escribe en ambas columnas
  2. Deploy 2: el código lee la columna nueva, sigue escribiendo en ambas
  3. Deploy 3: el código solo usa la columna nueva, elimina la escritura duplicada
  4. Migración final: elimina la columna vieja

Sí, son más pasos. Pero evitan el downtime y, más importante, evitan pérdida de datos.

Health checks: el prerequisito de todo lo anterior

Ninguna estrategia de deploy sin downtime funciona sin health checks correctos. El load balancer necesita saber cuándo una instancia está lista para recibir tráfico.

Un health check básico responde en /health con un status 200 cuando la aplicación está lista — conexión a la base de datos verificada, caché caliente, dependencias disponibles.

Si el health check falla, el load balancer no envía tráfico a esa instancia. Nunca.

// Ejemplo básico de health check endpoint
app.get('/health', async (req, res) => {
  try {
    await db.execute('SELECT 1'); // verificar conexión DB
    res.json({ status: 'ok', timestamp: new Date().toISOString() });
  } catch (error) {
    res.status(503).json({ status: 'error', message: 'Database unavailable' });
  }
});

Lo que usamos para proyectos en Railway

Railway hace que esto sea considerablemente más simple. Con su sistema de deploys, la nueva versión no recibe tráfico hasta que el health check pasa. Si el deploy falla, el tráfico sigue en la versión anterior automáticamente.

Para la mayoría de proyectos que construimos, esto es suficiente. Para proyectos que requieren zero-downtime absoluto o rollback instantáneo, implementamos blue-green con un proxy de Nginx o Caddy delante.


Si tu aplicación tiene deploys que generan downtime y quieres resolverlo, generalmente es una combinación de infraestructura correcta y migraciones de base de datos bien planificadas. Escríbenos si quieres revisarlo.

Compartir artículo

Hablemos

De tu idea
al
producto.

Una conversación de 15 minutos aclara más que un brief de 3 páginas. Te decimos si podemos ayudarte, cuánto costaría y cuándo estaría listo.

Iniciar proyecto WhatsApp directo

Respuesta en menos de 24h

Precio y alcance fijos por escrito Demos en vivo cada 2 semanas El código y los datos son tuyos