¿Por qué tu servicio no debería «echarse a dormir» a la hora de comer?
Imagina: viernes, 18:45. Acabas de lanzar la tan esperada actualización del servicio C#. Y al instante, llegan mensajes al chat de soporte: «el sitio no funciona», «error 503», «perdí los datos del carrito». ¿Te suena? Este es el escenario clásico donde un despliegue «a la brava» arruina la experiencia del usuario. En el mundo actual, donde cada hora de inactividad puede costar millones, el despliegue zero-downtime de servicios C# no es un lujo, sino una higiene básica del desarrollo.
En este artículo no daremos aburridas conferencias. Analizaremos estrategias reales para actualizar aplicaciones .NET sin detener su funcionamiento, escribiremos código para health checks y graceful shutdown, y mostraremos cómo configurar rolling update en Kubernetes. Si estás cansado de las «mágicas» caídas de producción después de cada commit, este material es para ti. ¡Allá vamos!
¿Qué es el zero-downtime deployment y por qué lo necesita un desarrollador C#?
Zero-downtime deployment (despliegue con tiempo de inactividad cero) es una metodología para actualizar una aplicación en la que la versión antigua sigue atendiendo solicitudes hasta que la nueva versión esté completamente operativa. El usuario no nota el cambio: ni errores, ni timeouts, ni pérdida de sesión.
Problemas principales al actualizar servicios C#
- Graceful shutdown no siempre funciona. El estándar
app.StopAsync()puede interrumpir solicitudes activas si no se configuran los timeouts. - Conexiones colgadas. La versión antigua mantiene WebSocket abiertos o solicitudes HTTP largas.
- Migraciones de BD. La nueva versión requiere cambios de esquema, y la antigua es incompatible con ellos.
- Caché y sesiones. Tras el cambio, el usuario pierde datos en memoria.
La buena noticia: C# y el ecosistema .NET proporcionan todas las herramientas para resolver estos problemas. Nuestra tarea es reunirlas en un sistema funcional.
Estrategia n.º 1: Blue-Green Deployment para C#
Este es el esquema más simple y fiable. Tienes dos entornos idénticos: Blue (versión actual) y Green (nueva versión). Despliegas la nueva versión en Green, ejecutas smoke-tests y luego cambias instantáneamente el balanceador de Blue a Green. Si algo sale mal, reviertes en un segundo.
¿Cómo implementarlo para .NET?
Necesitamos un balanceador (NGINX, HAProxy o un Load Balancer en la nube) y dos instancias de tu servicio C#. Ejemplo de configuración de NGINX:
upstream backend { server blue-server:5000 weight=100; server green-server:5000 weight=0; # Reserva}
server { listen 80; location / { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; }}Tras desplegar la versión Green, cambiamos los pesos: blue:0, green:100. Los usuarios migran imperceptiblemente a la nueva versión.
Ventajas: simplicidad, reversión instantánea.
Desventajas: se necesitan el doble de recursos (servidores).
Estrategia n.º 2: Rolling Update con Kubernetes (ideal para microservicios)
Kubernetes puede hacer rolling update «de fábrica». Reemplaza gradualmente los Pods antiguos por nuevos, sin interrumpir el tráfico. Pero para que funcione correctamente con C#, es necesario configurar health probes y graceful shutdown.
Health Checks en .NET 6/8
Añade a tu Program.cs un endpoint para verificar la preparación (readiness) y la vitalidad (liveness):
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks() .AddCheck<DatabaseHealthCheck>("database") .AddCheck<CacheHealthCheck>("redis");
var app = builder.Build();
app.MapHea