Monitorizează job-urile cu Healthchecks.io

Dacă rulezi cron job-uri, backup-uri automate sau orice alte sarcini periodice pe server, probabil ai întâlnit situația în care ceva a eșuat în liniște, fără să afli decât după câteva zile. Healthchecks rezolvă exact această problemă.

Ce este Healthchecks?

Healthchecks funcționează pe principiul “dead man’s switch”: job-ul tău trimite un semnal HTTP (ping) după ce s-a terminat cu succes. Dacă pingul nu sosește în intervalul de timp așteptat, Healthchecks trimite o alertă prin email, Telegram, Slack sau alte canale.

Este open-source (licență BSD), poate fi găzduit pe propriul server și vine cu o interfață web, API, peste 25 de integrări de notificări și suport pentru echipe. Imaginea Docker oficială suportă arhitecturi amd64, arm64 și arm/v7, deci merge și pe Raspberry Pi.

Instalare cu Docker Compose

Cea mai simplă cale de instalare este prin Docker Compose. Exemplul de mai jos folosește SQLite ca bază de date (suficient pentru uz personal sau o echipă mică). Dacă ai nevoie de ceva mai robust, Healthchecks suportă și PostgreSQL sau MySQL, configurabile prin variabilele DB_*.

Creează un director și fișierul docker-compose.yml:

mkdir -p ~/docker/healthchecks
cd ~/docker/healthchecks
nano docker-compose.yml

Conținutul fișierului:

version: "3"
services:
  healthchecks:
    image: healthchecks/healthchecks:latest
    container_name: healthchecks
    environment:
      - DB=sqlite
      - DB_NAME=/data/hc.sqlite
      - DEBUG=False
      - DEFAULT_FROM_EMAIL=noreply@exemplu.ro
      - EMAIL_HOST=smtp.exemplu.ro
      - EMAIL_HOST_PASSWORD=parola-smtp
      - EMAIL_HOST_USER=user-smtp
      - EMAIL_PORT=587
      - EMAIL_USE_TLS=True
      - SECRET_KEY=un-sir-aleatoriu-lung-si-secret
      - SITE_ROOT=https://hc.exemplu.ro
    ports:
      - 8000:8000
    volumes:
      - healthchecks-data:/data
    restart: unless-stopped
volumes:
  healthchecks-data:

Câteva observații:

  • SECRET_KEY trebuie să fie un șir aleatoriu și unic. Poți genera unul cu: openssl rand -hex 32
  • SITE_ROOT este URL-ul la care va fi accesibilă instanța ta
  • Imaginea nu gestionează TLS, deci în producție ai nevoie de un reverse proxy (nginx, Caddy etc.)

Pornește containerul:

docker compose up -d

Creează primul cont de administrator:

docker compose exec healthchecks /opt/healthchecks/manage.py createsuperuser

Interfața web va fi disponibilă la http://localhost:8000 (sau la domeniul configurat, prin reverse proxy).

Crearea primului check

După autentificare, dai click pe Add Check. Completezi:

  • Name - un nume descriptiv (ex: “Backup nocturn”)
  • Tags - opțional, pentru organizare
  • Period - intervalul în care aștepți pingul (ex: 1 day)
  • Grace time - marja de toleranță după expirarea perioadei (ex: 1 hour)

După salvare, fiecare check primește un UUID unic. URL-ul de ping va arăta astfel:

https://hc.exemplu.ro/ping/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Healthchecks suportă trei tipuri de ping:

  • success (URL simplu) - sarcina s-a terminat cu succes
  • fail (/ping/UUID/fail) - sarcina a eșuat explicit
  • start (/ping/UUID/start) - sarcina a început (util pentru a măsura durata)

Integrare cu cron

Cel mai simplu caz: un cron job care trimite ping după execuție.

0 3 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 3 https://hc.exemplu.ro/ping/UUID > /dev/null

Dacă vrei să raportezi și eșecul:

#!/bin/bash
UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
HC_URL="https://hc.exemplu.ro/ping/$UUID"

curl -fsS -m 10 "$HC_URL/start"

/usr/local/bin/backup.sh
EXIT_CODE=$?

if [ $EXIT_CODE -eq 0 ]; then
    curl -fsS -m 10 "$HC_URL"
else
    curl -fsS -m 10 "$HC_URL/fail"
fi

Integrare cu systemd

Dacă folosești systemd timers în loc de cron, integrarea se face prin servicii template. Avantajul față de cron este că poți include și ultimele loguri din journal în ping, ceea ce ușurează diagnosticarea problemelor.

Serviciile template

Creează /etc/systemd/system/healthchecks-notify@.service:

[Unit]
Description=Notifică Healthchecks (%i)

[Service]
Type=oneshot
ExecStart=/bin/bash -c '\
  IFS=: read -r UUID ACTION <<< "%i"; \
  if [ "$ACTION" = "start" ]; then \
    LOGS="" && EXIT_CODE="start"; \
  else \
    LOGS=$(journalctl --no-pager -n 50 -u $MONITOR_UNIT) \
    && EXIT_CODE=$MONITOR_EXIT_STATUS; \
  fi \
  && curl -fSs -m 10 --retry 3 --data-raw "$LOGS" \
     "https://hc.exemplu.ro/ping/$UUID/$EXIT_CODE"'

Înlocuiește https://hc.exemplu.ro cu URL-ul instanței tale.

Serviciul monitorizat

Adaugă hook-urile în unit-ul pe care vrei să-l monitorizezi, de exemplu /etc/systemd/system/backup-nocturn.service:

[Unit]
Description=Backup nocturn
OnSuccess=healthchecks-notify@UUID:success.service
OnFailure=healthchecks-notify@UUID:failure.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

Și timer-ul asociat /etc/systemd/system/backup-nocturn.timer:

[Unit]
Description=Rulează backup-ul nocturn zilnic

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

Activează timer-ul:

sudo systemctl daemon-reload
sudo systemctl enable --now backup-nocturn.timer

Cum funcționează :success și :failure

Sufixele :success și :failure sunt importante: fără ele, variabilele de mediu $MONITOR_UNIT și $MONITOR_EXIT_STATUS nu sunt transmise serviciului declanșat. Acestea sunt setate automat de systemd și conțin numele unit-ului monitorizat, respectiv codul de ieșire.

De exemplu, dacă backup-ul eșuează cu exit code 1, Healthchecks va primi pingul la /ping/UUID/1, va marca check-ul ca eșuat și va trimite notificarea configurată.

Configurarea notificărilor

Din interfața web, intri pe un check și dai click pe Add Integration. Sunt disponibile peste 25 de canale: email, Telegram, Slack, Gotify, Apprise, webhook-uri și altele. Pentru o instanță self-hosted izolată de internet, Gotify sau Apprise sunt opțiuni bune dacă nu vrei să depinzi de servicii externe.

Actualizarea instanței

docker compose pull
docker compose up -d

Migrările de bază de date rulează automat la pornirea containerului.


Documentația completă și lista tuturor variabilelor de configurare disponibile la: https://healthchecks.io/docs/self_hosted_configuration/