Back to 0cron
0cron

Monitoreo heartbeat: cuando tu tarea deberia hacerte ping

Como 0cron implementa monitoreo heartbeat -- cron inverso donde tus tareas hacen ping a una URL, y el silencio dispara alertas. 105 lineas de Rust.

Juste Thales Gnimavo & Claude | March 26, 2026 4 min 0cron
EN/ FR/ ES
0cronmonitoringheartbeatrustpostgresqlalerting

La mayor parte de 0cron funciona en una direccion: llamamos a tus endpoints en un horario. Pero hay una clase de problemas donde la direccion necesita invertirse. Tienes un script de respaldo ejecutandose en tu propio servidor. Un pipeline de CI que deberia completarse cada hora. Una tarea de sincronizacion de datos gestionada por un servicio de terceros. No puedes apuntar 0cron a estas porque no controlas su invocacion. Lo que necesitas saber es si siguen ejecutandose.

Esto es monitoreo heartbeat, y esta incorporado en 0cron como funcionalidad de primera clase. El concepto es simple: te damos una URL. Tu tarea hace ping a esa URL cuando se completa. Si no recibimos un ping dentro de la ventana esperada mas un periodo de gracia, te alertamos. Silencio significa fallo.

La implementacion completa son 105 lineas de Rust.

El modelo de datos

sqlCREATE TABLE monitors (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    team_id UUID REFERENCES teams(id),
    name VARCHAR(255) NOT NULL,
    ping_token VARCHAR(64) UNIQUE NOT NULL,
    schedule_cron VARCHAR(100) NOT NULL,
    grace_period_seconds INTEGER DEFAULT 300,
    timezone VARCHAR(50) DEFAULT 'UTC',
    status VARCHAR(20) DEFAULT 'active',
    last_ping_at TIMESTAMPTZ,
    notification_config JSONB,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

ping_token es una cadena hexadecimal unica de 64 caracteres (32 bytes aleatorios). Tokens en lugar de IDs de monitor por dos razones: los tokens son imposibles de adivinar y desacoplan el endpoint de ping del modelo de datos interno.

grace_period_seconds predeterminado en 300 (5 minutos). Una tarea que se ejecuta a las 2:00am y hace ping a las 2:04am no esta retrasada -- esta dentro de tolerancia.

last_ping_at es anulable. Un monitor nuevo nunca ha recibido un ping. No alertamos en monitores que nunca han hecho ping.

Generacion de tokens

rustfn generate_ping_token() -> String {
    use rand::Rng;
    let mut rng = rand::thread_rng();
    let bytes: Vec<u8> = (0..32).map(|_| rng.gen()).collect();
    hex::encode(bytes)
}

32 bytes aleatorios, codificados en hexadecimal a 64 caracteres. Eso son 256 bits de entropia -- mas combinaciones posibles que atomos en el universo observable.

Registro de pings

rustpub async fn record_ping(ping_token: &str, db: &PgPool) -> AppResult<()> {
    let now = Utc::now();
    let result = sqlx::query("UPDATE monitors SET last_ping_at = $1 WHERE ping_token = $2")
        .bind(now).bind(ping_token).execute(db).await?;
    if result.rows_affected() == 0 {
        return Err(AppError::NotFound(format!("Monitor with token '{ping_token}' not found")));
    }
    Ok(())
}

Una sola sentencia SQL. El endpoint de la API es GET /v1/ping/{token}. Si, GET, no POST. Las solicitudes GET son la solicitud HTTP mas simple posible. Funcionan con curl, con wget, e incluso pegando la URL en un navegador.

Deteccion de monitores vencidos

rustpub async fn check_monitors(db: &PgPool) -> AppResult<Vec<Monitor>> {
    let overdue = sqlx::query_as::<_, Monitor>(
        "SELECT * FROM monitors WHERE status = 'active'
         AND last_ping_at IS NOT NULL
         AND last_ping_at + (grace_period_seconds || ' seconds')::interval < NOW()",
    ).fetch_all(db).await?;
    Ok(overdue)
}

La expresion last_ping_at + (grace_period_seconds || ' seconds')::interval construye una marca de tiempo que representa "el ultimo ping mas el periodo de gracia." La aritmetica de intervalos de PostgreSQL es una funcionalidad de primera clase.

Casos de uso

Tareas de respaldo. Anade curl https://0cron.dev/v1/ping/TOKEN como la ultima linea de tu script. Si el respaldo falla, el curl nunca se ejecuta, y 0cron te alerta.

Pipelines CI/CD. Anade un ping al final del pipeline, establece el periodo de gracia a 1800 segundos. Si un despliegue se cuelga, la falta de ping dispara una alerta.

Salud de servicios externos. Monitoreo para un servicio que no controlas.

Dispositivos IoT. Un nodo sensor que deberia reportar cada 15 minutos. Si se calla, el patron de ping-y-silencio funciona.

105 lineas

Todo el monitoreo heartbeat -- modelo de datos, generacion de tokens, registro de pings, deteccion de vencidos -- son 105 lineas de Rust. Esto es posible porque tomamos decisiones agresivas de alcance. Una marca de tiempo en lugar de una tabla de historial. GET en lugar de POST. Periodos de gracia fijos en lugar de umbrales adaptativos.


Este es el articulo 8 de 10 en la serie "Como construimos 0cron".

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles

Thales & Claude deblo

El prompt decía que lo anunciara. El modelo no lo hizo. Así que lo hizo el worker: cerrar un silencio de 15 segundos en Déblo Voice

Déblo Voice se quedaba en silencio unos 15 segundos cada vez que una pregunta difícil activaba una búsqueda profunda. El prompt ya exigía un anuncio, pero el modelo de audio nativo emite la llamada a la función como su primer token. Además, el silencio tenía dos partes, la ejecución de la herramienta y la latencia de la respuesta, así que ningún prompt podía cerrarlo. Llevamos la garantía al worker de LiveKit: un anuncio pregrabado con la voz y el idioma de la sesión, y un suave sonido de tecleo mientras el agente piensa. Probado en producción el 16 de octubre de 2026: 14 y 17,5 segundos de silencio del lado del modelo, unos 0,4 segundos percibidos por el usuario.

13 min Oct 16, 2026
deblodeblo-voicevoice-aigemini-live +17
Thales & Claude zerosuite

El servidor que no dimos de baja: vaciar una máquina de producción en una noche, y cada número que comprobamos

Una noche, seis aplicaciones migradas fila por fila, tres copias de seguridad vacías, una sin destino y un servidor cuyo futuro cambió tres veces.

19 min Oct 2, 2026
caspclaude-codeclaude-opus-5.5infrastructure +10
Thales & Claude zerosuite

El orquestador no programa: trece sesiones en un día, un navegador que verifica y saber cuándo parar

Un día, una plataforma privada de un cliente, trece sesiones headless de Claude encadenadas por un orquestador que nunca escribe código. Verificar en el navegador del CEO, agrupar correcciones sin soltar la gate y escribir cuándo cerrar una sesión.

19 min Sep 30, 2026
caspclaude-codeclaude-opus-5.5multi-session +12