Guía9 min

Healthchecks para agentes IA en producción: Docker, Fly, Railway

Resumen

Cómo diseñar un endpoint /health que no mienta: liveness vs readiness para agentes, HEALTHCHECK en Docker, checks de Fly.io, healthchecks de Railway que solo corren en el deploy, y los errores que dejan tráfico en un proceso vivo pero sordo.

DockerRailway
Monitor de salud con un endpoint verde y otro rojo frente a un agente en producción

Qué resuelve

Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.

El agente ya está en Docker, Railway o Fly. El deploy “verde” no significa que responda. Un proceso vivo que no acepta webhooks es un 502 con el contenedor Up. El healthcheck es el contrato entre tu agente y la plataforma: si miente, la plataforma miente. Las fuentes oficiales fueron consultadas el 3 de septiembre de 2026.

Definición citable

Liveness: el proceso no está trabado. Si falla, hay que reiniciarlo. Readiness: el proceso puede aceptar tráfico ahora (modelo listo, conexión a BD, cola no saturada). Si falla, hay que dejar de mandarle requests, no necesariamente matarlo. Kubernetes documenta esa separación en probes de liveness, readiness y startup; las plataformas de builders suelen mezclarlas en un solo /health. Mezclarlas mal es el bug más caro: un check que pega al LLM en cada probe convierte un fallo del proveedor en un restart loop.

Qué debe hacer /health

Responde 200 rápido, sin llamar al modelo.

app.get("/health", (_req, res) => {
  res.status(200).json({ ok: true });
});

Eso es liveness. Si quieres readiness, añade una comprobación local (sqlite abre, Redis PING, el puerto interno responde) con timeout corto. Nunca:

  • Completar un chat de prueba contra OpenAI.
  • Esperar a que la cola se vacíe.
  • Depender de un servicio externo que tú no controlas.

Un agente “listo” es “acepta el webhook y encola”. No es “el LLM contestó”.

El check también es parte del contrato con CI/CD: si el job de deploy espera un 200 y /health llama al modelo, un corte de OpenAI bloquea Production. El pipeline debe pegar al mismo endpoint barato que Docker y Railway.

Cómo lo usa cada plataforma

Cómo Docker, Fly y Railway usan el healthcheck de un agente

PlataformaQué hace el checkCuándo correSi falla
Docker HEALTHCHECKCorre un comando dentro del contenedorDesde que arranca; estados startinghealthy / unhealthy tras fallos seguidosEl contenedor sigue Up; Compose/orquestador decide si lo recrea
RailwayGET al path que configuras, espera HTTP 200Solo durante el deploy, antes de cambiar tráficoNo activa el deployment nuevo; el anterior sigue
Fly.ioChecks de servicio (http_checks / tcp_checks) vs checks top-levelServicio: rutea tráfico; top-level: monitoreo, no saca la Machine del proxyUn check de servicio malo deja de mandarle requests
Caddy (VPS)El reverse proxy reintenta upstreams caídosEn cada request si el upstream no responde502 al cliente hasta que el agente vuelve

Railway lo dice claro: no monitorea el endpoint después de que el deploy quedó live. Si el agente se traba a las 3 h, Railway no se entera por el healthcheck. Ahí necesitas logs, un cron externo o un check de Fly/Docker que sí corre en loop.

Docker: instrucción mínima

HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
  CMD wget -qO- http://127.0.0.1:3000/health || exit 1

Docker documenta HEALTHCHECK CMD (correr un comando) y HEALTHCHECK NONE (anular el de la imagen base). El estado empieza en starting; pasa a healthy al primer OK; a unhealthy tras N fallos seguidos. En Compose, combina esto con restart: unless-stopped — el HEALTHCHECK solo marca, no reinicia solo.

Railway: path y PORT

  1. El agente sirve /health → 200 cuando puede aceptar requests.
  2. Service Settings → Healthcheck path: /health.
  3. El check usa la variable PORT que Railway inyecta. Si tu app ignora PORT, el check pega al puerto equivocado y el deploy nunca pasa a live.

Cero downtime de Railway = el nuevo deployment no recibe tráfico hasta el 200. No es un monitor 24/7.

Fly: no confundas los dos tipos

Los checks de servicio (services.http_checks o [[http_service.checks]]) sacan la Machine del ruteo. Los checks top-level sirven para alerta interna y no afectan el proxy. Un agente HTTP quiere el de servicio. Un worker de cola sin puerto público usa el top-level — Fly lo documenta para job runners.

Errores comunes

Errores típicos de healthchecks en agentes de producción

SíntomaCausa típicaFix
Restart loop cada 30 s/health llama al LLM y el proveedor fallaCheck local, sin red externa
Deploy Railway colgadoApp no escucha PORTBind a process.env.PORT
Fly manda tráfico a Machine fríaCheck de servicio ausente o demasiado laxohttp_checks con grace al arranque
Docker healthy y 502 en CaddyCheck pega a localhost interno; el proceso no escucha 0.0.0.0Bind correcto + el mismo /health que usa Caddy
“Cero downtime” y igual hay huecoRailway no vigila post-deployLogs + alerta externa; no asumas monitor continuo

Cuándo NO pongas un healthcheck “inteligente”

  • El agente es un cron de Workers: el runtime ya mata el isolate; un /health extra no aporta.
  • El check necesita más de 3 s: entonces no es health, es una eval. Muévelo a observabilidad.
  • Estás en Hobby de Vercel con un cron diario: el 200 del Route Handler al arrancar basta; no inventes un sidecar.

Checklist

  • /health responde 200 en < 50 ms, sin LLM
  • Liveness ≠ readiness si el agente tiene cola o BD
  • Docker: HEALTHCHECK CMD al localhost del contenedor
  • Railway: path + PORT; sabes que no monitorea después
  • Fly: check de servicio si hay HTTP público
  • El proxy (Caddy/Fly) y el HEALTHCHECK pegan al mismo bind

Siguiente paso: combina esto con observabilidad — el healthcheck dice si el proceso vive; los evals y traces dicen si el agente acierta. Si todavía no tienes runtime, el curso gratuito deja un agente local para añadirle /health antes del deploy.