Voltar ao blog

Monitorizar tarefas cron: o padrão heartbeat na prática

· 6 min de leitura

A monitorização HTTP não lhe dirá que um cron noturno falhou. O padrão heartbeat inverte o sentido: o cron reporta-se à monitorização e, se não chamar a tempo, recebe um alerta.

Monitorizar tarefas cron: o padrão heartbeat na prática

O problema: tarefas em segundo plano sem endpoint HTTP

Um backend típico tem vários caminhos:

  • Pedidos web (HTTP/HTTPS para o servidor) - monitoriza-os com um uptime check.
  • Tarefas cron (backup diário, faturação mensal, sincronização horária) - não têm endpoint HTTP, a monitorização externa não consegue segui-las.
  • Workers (Celery, BullMQ, Sidekiq) que processam uma fila - também sem HTTP.

Quando um cron falha (um erro de digitação no crontab, um disco cheio, uma variável de ambiente (environment variable) em falta ou um erro de import depois de atualizar uma dependência (dependency upgrade)), ninguém o avisa. Descobre-o na segunda-feira de manhã, ao reparar que nenhuma fatura saiu durante o fim de semana.

O padrão heartbeat: o cron faz ping à monitorização

O princípio é inverso ao da monitorização normal:

  1. No serviço de monitorização cria um monitor heartbeat com um intervalo esperado (por exemplo "a cada 60 minutos").
  2. Recebe uma URL heartbeat única: https://epulz.io/heartbeat/abc123xyz.
  3. Na sua tarefa cron, no final de uma execução bem-sucedida, chama essa URL (HTTP GET ou POST).
  4. Se o ping não chegar dentro do tempo esperado (mais um período de tolerância), a monitorização avisa-o.

Exemplo prático: heartbeat a partir de uma tarefa cron

# /etc/crontab
0 3 * * * www-data /usr/local/bin/backup.sh && curl -fsS -m 10 \
  https://epulz.io/heartbeat/abc123xyz > /dev/null

A chave é o operador &&: o heartbeat é enviado apenas quando o backup.sh termina com código de saída 0. Se o script falhar, o ping não chega e dentro de uma hora recebe um alerta.

Dica: Para uma cobertura mais completa, adicione também um heartbeat "start":

curl -fsS -m 10 https://epulz.io/heartbeat/backup-start-xyz > /dev/null
/usr/local/bin/backup.sh && \
  curl -fsS -m 10 https://epulz.io/heartbeat/backup-done-xyz > /dev/null

A monitorização pode então distinguir "começou mas não terminou" (o script bloqueou) de "nunca começou" (a tarefa cron não foi executada).

Python: requests + try/except

import os, requests
HEARTBEAT_URL = os.environ["HEARTBEAT_URL"]

def sync_data():
    # ... your logic ...
    pass

try:
    sync_data()
    requests.get(HEARTBEAT_URL, timeout=10)
except Exception as e:
    # O heartbeat não é enviado - a monitorização avisa-o
    raise

Node.js: async / await

const HEARTBEAT_URL = process.env.HEARTBEAT_URL;

async function nightlyJob() {
  await processInvoices();
  await fetch(HEARTBEAT_URL, { signal: AbortSignal.timeout(10000) });
}

nightlyJob().catch(err => {
  console.error(err);
  process.exit(1);
});

Período de tolerância: quanto tempo dar antes do alerta

Um monitor heartbeat precisa de alguma tolerância. O cron por vezes corre mais tempo do que o habitual, a rede tem latência e a sincronização NTP pode estar ligeiramente desfasada. O período de tolerância (grace period) é o tempo, após o intervalo esperado expirar, durante o qual a monitorização ainda espera antes de disparar um alerta.

Valores práticos:

  • Cron horário: intervalo 60 min + tolerância 10 min
  • Backup diário (em média 20 min): intervalo 1440 min + tolerância 60 min
  • Relatório semanal: intervalo 10080 min + tolerância 360 min (6 h)

Uma tolerância demasiado apertada = alertas falsos (falsos positivos). Demasiado folgada = um alerta atrasado precisamente quando a tarefa falha de verdade.

Onde o padrão heartbeat ajuda mais

  • Backups de BD noturnos
  • Sincronização com API externas (CRM, contabilidade, pagamentos)
  • Cálculos de relatórios
  • Tarefas de cleanup (apagar sessões antigas, logs, ficheiros temporários)
  • O ciclo de healthcheck de workers de longa duração
  • E-mails, newsletters e faturação agendados

Conclusão

As tarefas em segundo plano (background) costumam ser mais críticas do que o próprio site, mas continuam a ser um ponto cego da monitorização. O padrão heartbeat exige apenas cinco minutos de implementação (basta adicionar curl no fim da linha cron) e oferece a mesma garantia que a monitorização uptime do frontend.

Lembrete rápido: sintaxe cron

A maioria dos erros de heartbeat são, na verdade, erros de cron - o ping nunca dispara porque o agendamento estava errado. Os cinco campos são:

┌── minuto (0-59)
│ ┌── hora (0-23)
│ │ ┌── dia do mês (1-31)
│ │ │ ┌── mês (1-12)
│ │ │ │ ┌── dia da semana (0-7, 0 e 7 = domingo)
│ │ │ │ │
* * * * *  comando
Expressão Executa
*/5 * * * * a cada 5 minutos
0 * * * * no início de cada hora
0 3 * * * todos os dias às 03:00
0 3 * * 1 todas as segundas-feiras às 03:00
30 2 1 * * às 02:30 do primeiro dia do mês

A armadilha clássica: */5 no campo hora não significa "a cada 5 horas a partir de agora", mas as horas divisíveis por cinco (0, 5, 10, 15, 20). Se o intervalo esperado do monitor e o agendamento cron real não coincidirem, recebe alertas fantasma.

O princípio do "dead man's switch"

O padrão heartbeat é um dead man's switch (interruptor de homem morto): o alarme é o silêncio. Isto inverte o modo de falha habitual. A monitorização normal pode falhar em silêncio - se o próprio servidor de monitorização cair, simplesmente deixa de enviar alertas e nunca fica a saber. O heartbeat é o oposto: o gatilho de um alerta é a ausência de um sinal esperado, por isso uma tarefa que para de correr por completo (todo o servidor desligado, o daemon cron desativado, a máquina desativada e esquecida) é exatamente o caso que ele apanha melhor.

Para além do cron: outros agendadores

O padrão é o mesmo independentemente do que dispara a tarefa: - timers systemd - adicione curl à cadeia ExecStart ou ao ExecStartPost=. Emparelhe o timer OnCalendar= com um intervalo de heartbeat correspondente. - Kubernetes CronJob - o último passo do contentor faz ping à URL heartbeat. Se o pod falhar ou nunca for agendado (node selector errado, falha de image pull), o ping falta e recebe um alerta. - Windows Task Scheduler - termine a tarefa com o comando PowerShell Invoke-WebRequest -Uri $env:HEARTBEAT_URL -TimeoutSec 10. - CI / pipelines agendados - um GitHub Actions noturno ou um schedule GitLab pode, como último passo, fazer ping ao heartbeat para confirmar que a pipeline correu e passou.

Anti-padrões comuns

  • Fazer ping no início, não no fim. Um heartbeat enviado antes do trabalho prova apenas que a tarefa começou. Coloque-o depois do trabalho, condicionado ao sucesso (&&), para que uma falha a meio da execução também retenha o ping.
  • Ignorar o código de saída. backup.sh; curl ... (ponto e vírgula) envia o ping mesmo que o backup tenha falhado. Use sempre &&.
  • Engolir em silêncio as falhas do curl. -fsS faz o curl falhar de forma audível num erro HTTP, para que os logs da sua tarefa mostrem que o heartbeat não pôde ser entregue (um problema de rede na máquina).
  • Um heartbeat para dez tarefas. Se cinco crons partilharem uma URL, não sabe qual deixou de correr. Dê a cada tarefa agendada o seu próprio heartbeat. Se também expuser um endpoint HTTP para o mesmo serviço, emparelhe o heartbeat com um uptime check normal e uma verificação de porta na porta do worker, para cobrir tanto "o processo está a correr" como "a execução agendada aconteceu".

Cenário concreto: a falha silenciosa do backup

O caso de manual para um heartbeat é assim. Um pg_dump noturno escreve num volume montado. Funciona durante meses. Depois o volume enche, o pg_dump termina com código diferente de zero e, como a linha cron usava um ponto e vírgula simples, o heartbeat é enviado na mesma e o dashboard fica verde. Três semanas depois a base de dados está corrompida e não há backup utilizável, porque cada backup "bem-sucedido" desde que o disco encheu foi um ficheiro de zero bytes. O padrão heartbeat apanha isto logo na primeira noite, mas apenas se estiver ligado corretamente: condicione o ping com && para que uma saída diferente de zero o retenha, e considere verificar o output, não apenas o código de saída. Um script de backup pode terminar com código 0 e ainda assim produzir um ficheiro truncado. Uma linha mais defensiva verifica que o dump não é trivial antes de sinalizar sucesso:

/usr/local/bin/backup.sh && \
  test "$(stat -c%s /backups/db.sql.gz)" -gt 1000000 && \
  curl -fsS -m 10 https://epulz.io/heartbeat/abc123xyz > /dev/null

Agora o heartbeat só chega se o script teve sucesso e o ficheiro resultante tiver mais de 1 MB. Qualquer coisa mais pequena e o ping é retido, e recebe um alerta dentro do período de tolerância em vez de três semanas depois.

Comece a monitorizar as suas tarefas cron

A ePulz.io suporta heartbeat checks com um período de tolerância configurável. 7 dias grátis.

Iniciar monitorização →

Relacionados

Partilhar: Link copiado

Experimente o ePulz.io grátis - 7 dias sem cartão de crédito.

Criar conta