Guides 7 min de lectura

Cómo crear un endpoint de health check (y monitorizarlo)

Un endpoint de health check indica a los monitores y balanceadores de carga si tu aplicación puede atender peticiones. Qué comprobar, cómo hacerlo rápido y seguro, código para Laravel, Express y Flask, y cómo monitorizarlo.

Un endpoint de health check es una URL, normalmente /health, que indica a un monitor o a un balanceador de carga si tu aplicación puede atender peticiones. Ejecuta unas cuantas comprobaciones rápidas sobre aquello de lo que depende la aplicación, como la base de datos, la caché y el espacio libre en disco, y responde con HTTP 200 y {«status»:»ok»} cuando todo funciona, o con HTTP 503 y el nombre de la comprobación que falla cuando algo no va bien. Hazlo rápido, barato, sin caché y sin secretos, y apunta a él un monitor de uptime que valide la respuesta, no solo el código de estado.

Esta guía explica la diferencia entre liveness y readiness, qué comprobar, el formato de la respuesta, ejemplos funcionales para PHP con Laravel, Node con Express y Python con Flask, y cómo monitorizar el endpoint una vez creado.

Por qué la página de inicio no es un health check

La mayoría de los equipos empiezan monitorizando la página de inicio. Es un primer paso razonable, pero la página de inicio suele servirse desde un CDN o una caché de páginas, así que sigue respondiendo 200 mientras la base de datos está caída y nadie puede iniciar sesión ni completar una compra. Un endpoint dedicado se salta la caché y pone a prueba directamente las dependencias. Además, te da una única URL predecible con una respuesta pequeña y estable que es fácil de validar.

Liveness frente a readiness

Las plataformas de contenedores como Kubernetes dividen la salud en dos preguntas, y esa división es útil en cualquier entorno:

Liveness: ¿el proceso está vivo y no se ha quedado bloqueado? Si no, reinícialo. Una comprobación de liveness no debería probar la base de datos ni otros servicios. Si la base de datos se cae y todas las instancias de la aplicación fallan su comprobación de liveness, la plataforma las reinicia todas, lo que no arregla la base de datos y hace que la recuperación sea más lenta.

Readiness: ¿esta instancia puede atender peticiones reales ahora mismo? Si no, deja de enviarle tráfico. Aquí es donde van las comprobaciones de dependencias.

Una estructura habitual es /livez o /up para liveness, que devuelve 200 siempre que la aplicación arranque, y /health o /readyz para readiness. Para la monitorización de uptime externa, el que interesa es el endpoint de readiness, porque responde a la pregunta que les importa a tus clientes: ¿funciona la aplicación?

Qué comprobar

Comprueba las dependencias sin las que una petición normal fallaría, y nada más:

Base de datos: ejecuta SELECT 1 en el mismo pool de conexiones que usa la aplicación. Demuestra que el servidor es accesible y acepta consultas.

Caché o almacén de sesiones: escribe y lee una clave de vida corta en Redis o Memcached. Si las sesiones se guardan ahí, el inicio de sesión depende de ello.

Disco: comprueba el espacio libre del volumen en el que escribe la aplicación, ya sea para subidas, logs o sesiones. Haz que falle cuando baje de un margen, por ejemplo el 10 por ciento.

Cola: comprueba que el backend de la cola responde y, si quieres, que el trabajo más antiguo en espera no supera un límite que tú elijas. Una cola que no deja de crecer significa que los workers se han parado.

Ten cuidado con las APIs de terceros. Si tu endpoint llama a un proveedor de pagos en cada comprobación y el proveedor va lento, tu health check falla aunque tu propia aplicación esté bien, y un balanceador de carga puede sacar de rotación todas las instancias. Es mejor monitorizar a los terceros con sus propios monitores, para que una alerta te diga de quién es el problema. La monitorización de terceros de Uptimecheck sigue las páginas de estado de 31 servicios como Klarna, Swish, Shopify, Cloudflare y OpenAI, o cualquier página alojada en Statuspage.

Hazlo rápido y barato

Un health check se ejecuta cada minuto desde cada monitor y cada balanceador de carga, las 24 horas del día. Nunca debe convertirse en lo que sobrecarga la aplicación.

Da a cada comprobación de dependencias su propio timeout corto, por ejemplo de uno o dos segundos, para que un servicio que se cuelga no cuelgue el endpoint.

Ejecuta las comprobaciones en paralelo cuando tu lenguaje lo ponga fácil.

Usa consultas triviales. Nunca cuentes las filas de una tabla grande ni generes un informe.

Si muchos comprobadores consultan el endpoint, guarda el resultado en memoria durante unos segundos.

Envía Cache-Control: no-store y excluye la ruta de las cachés de páginas y de los CDN, para no ver nunca un «ok» en caché.

Prescinde de las sesiones, las cookies y el middleware de autenticación que el endpoint no necesite.

No filtres secretos

Un endpoint de salud público está a la vista de cualquiera que adivine /health. Devuelve el nombre y el estado de cada comprobación, y nada más. No incluyas mensajes de excepción, cadenas de conexión, nombres de host, direcciones IP internas, versiones de software ni variables de entorno. Registra el error detallado en el servidor. Si quieres una vista de diagnóstico más completa, ponla en una ruta aparte protegida con autenticación o limítala a tu red interna.

Formato de la respuesta y códigos de estado

Mantén el JSON pequeño y estable:

{
«status»: «ok»,
«checks»: {
«database»: «ok»,
«cache»: «ok»,
«disk»: «ok»,
«queue»: «ok»
}
}

Cuando una comprobación falla, pon su valor a «fail», pon el estado general a «fail» y cambia el código de estado HTTP:

200 OK cuando pasan todas las comprobaciones obligatorias.

503 Service Unavailable cuando falla una comprobación obligatoria. Es el código que los balanceadores de carga y los monitores esperan para «temporalmente no puedo atender».

Opcionalmente, 200 con «status»:»degraded» para una dependencia opcional que está caída mientras el núcleo sigue funcionando. Decide de antemano qué comprobaciones son obligatorias.

Evita devolver 200 con «status»:»fail» en el cuerpo. Muchas herramientas solo leen el código de estado. Consulta códigos de estado HTTP para la monitorización para ver cómo se suele tratar cada código.

Ejemplo: PHP y Laravel

Las versiones recientes de Laravel incluyen una ruta sencilla /up que confirma que la aplicación arranca, lo que sirve como buena comprobación de liveness. Para readiness, añade una ruta que compruebe las dependencias:

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;

Route::get(‘/health’, function () {
$checks = [];

try {
DB::select(‘SELECT 1’);
$checks[‘database’] = ‘ok’;
} catch (\Throwable $e) {
report($e);
$checks[‘database’] = ‘fail’;
}

try {
Cache::put(‘health-check’, ‘ok’, 10);
$checks[‘cache’] = Cache::get(‘health-check’) === ‘ok’ ? ‘ok’ : ‘fail’;
} catch (\Throwable $e) {
report($e);
$checks[‘cache’] = ‘fail’;
}

$path = storage_path();
$checks[‘disk’] = disk_free_space($path) / disk_total_space($path) > 0.10 ? ‘ok’ : ‘fail’;

$healthy = ! in_array(‘fail’, $checks, true);

return response()
->json([‘status’ => $healthy ? ‘ok’ : ‘fail’, ‘checks’ => $checks], $healthy ? 200 : 503)
->header(‘Cache-Control’, ‘no-store’);
});

Regístrala fuera de los grupos de middleware que inician sesiones y configura un timeout de conexión corto para la base de datos.

Ejemplo: Node y Express

const withTimeout = (promise, ms) =>
Promise.race([
promise,
new Promise((_, reject) => setTimeout(() => reject(new Error(‘timeout’)), ms)),
]);

const check = (fn) => withTimeout(fn(), 2000).then(() => ‘ok’, () => ‘fail’);

app.get(‘/health’, async (req, res) => {
const [database, cache] = await Promise.all([
check(() => pool.query(‘SELECT 1’)),
check(() => redis.ping()),
]);

const checks = { database, cache };
const healthy = Object.values(checks).every((v) => v === ‘ok’);

res
.set(‘Cache-Control’, ‘no-store’)
.status(healthy ? 200 : 503)
.json({ status: healthy ? ‘ok’ : ‘fail’, checks });
});

Las comprobaciones se ejecutan en paralelo, cada una con un límite de dos segundos, así que el endpoint responde en unos dos segundos aunque una dependencia se cuelgue.

Ejemplo: Python y Flask

import shutil
from flask import jsonify
from sqlalchemy import text

@app.get(«/health»)
def health():
checks = {}

try:
db.session.execute(text(«SELECT 1»))
checks[«database»] = «ok»
except Exception:
app.logger.exception(«health: database»)
checks[«database»] = «fail»

usage = shutil.disk_usage(«/»)
checks[«disk»] = «ok» if usage.free / usage.total > 0.10 else «fail»

healthy = all(value == «ok» for value in checks.values())
body = {«status»: «ok» if healthy else «fail», «checks»: checks}
return jsonify(body), 200 if healthy else 503, {«Cache-Control»: «no-store»}

Añade una comprobación de Redis del mismo modo si lo usas para las sesiones o para una cola de tareas.

Prueba el camino del fallo

Un health check que nunca ha fallado nunca se ha probado. En staging, detén la base de datos o apunta la aplicación a un host de caché incorrecto y confirma que el endpoint devuelve 503 dentro de tu timeout y señala la comprobación correcta. Después confirma que la respuesta no contiene ningún texto de error. Lleva diez minutos y te garantiza que el endpoint dirá la verdad cuando importe.

Monitorizar el endpoint

Un endpoint que nadie comprueba desde fuera es solo la mitad del trabajo. Apunta a él un monitor HTTP desde fuera de tu red, para detectar también problemas de DNS, TLS, firewall y balanceador de carga:

Monitoriza https://lumenanalytics.io/health con GET cada minuto.

Espera el estado 200 y valida que el cuerpo contiene «status»:»ok». Así, una página de error de un proxy que casualmente devuelva 200 seguirá haciendo fallar la comprobación.

Envía una cabecera de user agent personalizada, para que el tráfico de monitorización sea fácil de filtrar en la analítica y los logs.

Vigila el historial de tiempos de respuesta. Un health check que pasa poco a poco de 40 ms a 900 ms es un aviso temprano de una base de datos con problemas.

Envía la alerta a las personas responsables del servicio.

La monitorización de APIs de Uptimecheck admite métodos y cabeceras personalizados (incluida la autenticación básica o un bearer token) y valida el estado esperado, las palabras clave y los campos JSON, así que esta configuración lleva un minuto. Mantén a la vez un monitor de uptime normal en la página de inicio y en la página de conversión más importante; la checklist de monitorización de APIs repasa los demás endpoints que vale la pena vigilar.

Los workers de colas y las tareas programadas suelen ejecutarse fuera del proceso web, así que un endpoint de salud no puede ver si se han parado. Para ellos, usa heartbeats: el worker hace ping a una URL cada pocos minutos, y si falta un ping salta la alerta.

Checklist del endpoint de health check

Separa liveness (el proceso está vivo) de readiness (las dependencias funcionan).

Comprueba la base de datos, la caché, el disco y la cola que la aplicación necesita para atender una petición.

Da a cada comprobación un timeout corto y mantén las consultas triviales.

Devuelve 200 cuando todo está bien y 503 cuando falla una comprobación obligatoria.

Devuelve solo los nombres y estados de las comprobaciones. Ni errores, ni versiones, ni nombres de host.

Desactiva la caché para la ruta.

Monitorízalo cada minuto desde fuera, con validación de la respuesta.

Uptimecheck monitoriza endpoints de salud, APIs, servidores y tareas programadas desde una sola cuenta. Empieza una prueba gratuita de 14 días, sin tarjeta de crédito.

Preguntas

¿Qué debe devolver un endpoint de health check?

Un cuerpo JSON pequeño con un estado general y el estado de cada comprobación, con HTTP 200 cuando todo lo obligatorio funciona y HTTP 503 cuando falla una comprobación obligatoria.

¿Un health check debe probar la base de datos?

La comprobación de readiness sí, con una consulta trivial como SELECT 1 y un timeout corto. La de liveness no, porque entonces una caída de la base de datos reiniciaría todas las instancias de la aplicación.

¿Es seguro hacer público un endpoint de salud?

Sí, si solo devuelve los nombres y estados de las comprobaciones. Deja fuera de la respuesta los mensajes de error, las versiones, los nombres de host y los datos de conexión, y regístralos en el servidor.

¿Cada cuánto hay que monitorizar un endpoint de health check?

Cada minuto en los servicios de producción. Valida que el cuerpo contiene el estado esperado además del código de estado, para que no pase por buena una página en caché o una página de error de un proxy.

Sigue leyendo

Guides 7 min de lectura

Cómo reducir las falsas alertas en la monitorización de uptime

Las falsas alertas enseñan a los equipos a ignorar la monitorización. Cómo reducir el ruido: confirma cada fallo con una segunda comprobación, fija timeouts razonables, valida la URL correcta y envía las alertas a quien puede actuar.

Leer

Guides 5 min de lectura

Checklist de monitorización de API: más allá del 200 OK

Una API puede devolver 200 y aun así estar rota. Un checklist práctico para monitorizar API: métodos, cabeceras, cuerpos de petición, autenticación, respuestas esperadas y umbrales de tiempo de respuesta.

Leer

Guides 4 min de lectura

El coste de una caída web: cómo calcular el tuyo

¿Cuánto cuesta de verdad una hora sin servicio? Una fórmula sencilla para los costes directos y ocultos de una caída, ejemplos prácticos y qué significan en dinero los porcentajes de uptime.

Leer

Las caídas son cosa del pasado.

Configura tu primer monitor en menos de un minuto, o echa antes un vistazo a la demo en vivo.

14 días de prueba gratis · Después, gratis con 5 monitores · Sin tarjeta de crédito