Comment monitorer un cron job avec Pinguro
Un cron qui plante en silence peut faire dérailler une facturation, un backup ou une synchro pendant des semaines avant d'être repéré. Voici comment installer un heartbeat Pinguro en cinq minutes pour ne plus jamais découvrir un job mort par hasard.
Pourquoi un cron qui plante silencieusement est dangereux
Un cron job réussit en silence et échoue en silence. Tant que personne ne va lire les logs, rien ne signale qu'il a cessé de tourner. Et il y a beaucoup de raisons pour qu'il s'arrête sans crier : binaire renommé après un déploiement, variable d'environnement perdue après une rotation de secrets, disque plein, version de Python mise à jour qui casse une dépendance, conteneur recréé sans la crontab recopiée, ou tout simplement la VM qui a redémarré et nginx qui est revenu, mais pas le service de jobs.
Les exemples concrets ne manquent pas. Le backup PostgreSQL nocturne qui ne tourne plus depuis trois semaines : tu t'en aperçois le jour où tu en as besoin pour restaurer. La facturation Stripe mensuelle qui n'a pas généré les factures du mois : tu t'en aperçois quand un client poli te demande où est sa note. La synchro CRM toutes les heures qui ne pousse plus rien : tu t'en aperçois quand le commercial te dit qu'il ne voit pas les leads d'hier dans Pipedrive.
Le piège, c'est que le monitoring HTTP classique ne couvre pas ce cas. Tu peux pinger ton serveur toutes les minutes : il répondra 200 OK, le SSL sera valide, le DNS résoudra. Pendant ce temps, sur la même machine, le job qui devait tourner à 3 h n'a rien fait. Les logs ne déclenchent pas d'alerte parce qu'il n'y a pas d'erreur dans les logs : il n'y a juste rien. Pas de signal négatif à intercepter — tu cherches l'absence d'un signal positif. C'est exactement le problème qu'un heartbeat résout.
Qu'est-ce qu'un heartbeat monitor ?
Un heartbeat — qu'on appelle aussi dead man's switch en clin d'œil aux trains — c'est l'inverse du monitoring HTTP classique.
- Monitoring HTTP : Pinguro envoie une requête vers ton serveur à intervalle régulier. Si la réponse est mauvaise ou absente, alerte.
- Heartbeat : ton job envoie une requête vers Pinguro à chaque exécution réussie. Si Pinguro ne reçoit rien dans la fenêtre attendue, alerte.
Schématiquement :
La logique de déclenchement est simple : tu déclares un intervalle attendu (par exemple, « ce job doit tourner toutes les heures ») et un délai de grâce (« mais je tolère 5 minutes de retard »). Tant que Pinguro reçoit un ping dans la fenêtre intervalle + grâce, le monitor reste vert. Dès que la fenêtre est dépassée sans signal, le monitor passe en panne et tu reçois une alerte sur les canaux configurés (Email, Slack, Discord, Telegram, webhook).
Avantage clé : on ne teste plus la santé apparente du serveur, on teste l'exécution effective du job. C'est binaire, factuel, sans interprétation possible. Si ton cron a tourné jusqu'au bout et envoyé son ping, c'est qu'il a fait son travail.
Configurer un heartbeat sur Pinguro
La mise en place prend littéralement deux minutes. Voici la procédure pas à pas.
1. Crée ton compte (gratuit)
Le plan gratuit Pinguro inclut 3 monitors, tous types confondus (HTTP, DNS, TCP, Heartbeat). Pas de carte bancaire à entrer, pas d'essai limité dans le temps. Inscris-toi sur pinguro.app/dashboard et valide ton email.
2. Crée le monitor heartbeat
Dans le dashboard, va sur Monitors → + Ajouter un monitor. Choisis le type Heartbeat / Cron. Tu vas remplir trois champs :
- Nom : donne un nom parlant. Pas
heartbeat 1maisBackup nocturne PostgreSQL — prod. Tu te remercieras dans six mois quand le téléphone sonnera à 3 h. - Intervalle attendu : la fenêtre maximale entre deux pings. Choix possibles de 1 minute à 30 jours. Pour un cron quotidien, mets 1 jour. Pour une synchro horaire, mets 1 heure.
- Délai de grâce : la marge tolérée par-dessus l'intervalle. Par défaut 5 minutes. À ajuster selon la durée d'exécution du job (un backup qui tourne 20 minutes a besoin d'au moins 25 minutes de grâce, sinon tu vas être alerté pendant qu'il s'exécute).
3. Récupère ton URL de ping
Une fois le monitor créé, Pinguro génère un token unique. Ton URL de ping ressemble à :
https://pinguro.app/h/<TON_TOKEN>
Cette URL accepte aussi bien GET que POST. Tu peux la pinger avec n'importe quel client HTTP : curl, wget, requests en Python, fetch en Node, etc. Pas besoin d'authentification : le token est l'authentification.
Le token est secret. Considère-le comme un mot de passe : ne le commit pas dans Git, mets-le dans une variable d'environnement ou un secret manager. Si tu le perds dans un repo public, régénère-le depuis le dashboard.
Intégrer le ping dans ton cron
C'est ici que le terrain devient concret. Voici les patterns qui marchent dans la vraie vie, par environnement.
Linux cron classique
Le pattern de base, à mettre dans ta crontab :
0 3 * * * /usr/local/bin/backup.sh && curl -fsS https://pinguro.app/h/TON_TOKEN > /dev/null
Trois détails sont importants :
&&(et non;) : le ping ne part que sibackup.shretourne un code de sortie 0. Si le backup échoue, pas de ping, et Pinguro alerte. Avec;tu ping quoi qu'il arrive, ce qui annule l'intérêt du heartbeat.curl -fsS:-fpour échouer sur les codes HTTP >= 400,-spour silencieux (pas de barre de progression dans les logs cron),-Spour quand même afficher les erreurs si-sest actif. C'est la combinaison standard pour les scripts.> /dev/null: on jette la sortie pour ne pas polluer les mails de cron. Si tu veux garder une trace, redirige vers un fichier de log applicatif.
Pour les jobs un peu plus longs, sépare les deux étapes :
0 3 * * * /usr/local/bin/backup.sh > /var/log/backup.log 2>&1 && curl -fsS https://pinguro.app/h/TON_TOKEN > /dev/null
Python
Pour un script Python, encapsule le ping dans une fonction qui ne crashe jamais : tu ne veux pas qu'une coupure réseau côté Pinguro fasse exploser ton job.
import requests
PING_URL = "https://pinguro.app/h/TON_TOKEN"
def heartbeat():
try:
requests.get(PING_URL, timeout=10)
except Exception:
# Si Pinguro est injoignable, on ne casse pas le job.
# Le monitor passera en panne au prochain check, ce qui est OK.
pass
def main():
do_backup()
sync_to_s3()
heartbeat()
if __name__ == "__main__":
main()
Note le timeout=10 : sans timeout explicite, requests attend indéfiniment. Si jamais Pinguro est dans un mauvais jour, ton job s'éterniserait. Dix secondes suffisent largement pour un ping.
GitHub Actions
Pour un workflow planifié (build de docs, scraper, sync de données), ajoute le ping comme dernière étape, conditionnée à la réussite du job :
name: Daily sync
on:
schedule:
- cron: '0 4 * * *'
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run sync
run: ./scripts/sync.sh
- name: Notify Pinguro
if: success()
run: curl -fsS "https://pinguro.app/h/${{ secrets.PINGURO_HEARTBEAT_TOKEN }}"
Le if: success() est essentiel : il garantit que le ping ne part qu'en cas de succès complet du job précédent. Stocke le token dans Settings → Secrets and variables → Actions, jamais en clair dans le YAML.
Kubernetes CronJob
Pour un CronJob Kubernetes, deux approches possibles. La plus simple : appeler curl à la fin du script principal, comme en cron classique. La plus propre, si ton conteneur applicatif n'a pas curl : enchaîner deux conteneurs avec command et shareProcessNamespace, ou plus simplement utiliser initContainers à l'envers via un script wrapper.
Voici la version simple, lisible, qui marche dans 95 % des cas :
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-backup
spec:
schedule: "0 3 * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: my-org/backup:latest
env:
- name: PINGURO_TOKEN
valueFrom:
secretKeyRef:
name: pinguro-secrets
key: heartbeat-token
command:
- /bin/sh
- -c
- |
/app/backup.sh && \
wget -q -O /dev/null "https://pinguro.app/h/$PINGURO_TOKEN"
On utilise wget ici parce que beaucoup d'images alpine ne livrent pas curl par défaut. Le token vient d'un Secret Kubernetes, jamais inscrit dans la définition du CronJob.
Systemd timer
Si tu es passé à systemd.timer au lieu de cron (recommandé sur les distros récentes pour bénéficier du logging via journalctl), ajoute le ping dans la section ExecStartPost du service, qui ne s'exécute qu'en cas de succès :
[Unit]
Description=Backup nocturne PostgreSQL
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
ExecStartPost=/usr/bin/curl -fsS https://pinguro.app/h/TON_TOKEN
[Install]
WantedBy=multi-user.target
Si ExecStart échoue, ExecStartPost n'est pas appelé : exactement le comportement qu'on veut.
Configure ton premier heartbeat en deux minutes
Plan gratuit avec 3 monitors, sans carte bancaire. Tu peux supprimer ton compte à tout moment.
Créer mon compte gratuitBonnes pratiques
Choisis l'intervalle avec une marge réaliste
La règle simple : intervalle = fréquence cron + durée d'exécution + marge réseau. Pour un cron quotidien à 3 h qui prend 30 minutes à tourner, tu veux un intervalle de 24 h et une grâce d'au moins 1 h, pas 5 minutes. Sinon tu vas recevoir des fausses alertes les jours où le job met 35 minutes au lieu de 28.
À l'inverse, ne configure pas un intervalle de 7 jours pour un cron quotidien : si le job rate trois fois de suite, tu ne le sauras qu'au bout de la semaine. Le but du heartbeat, c'est de réduire le temps de détection, pas de le rallonger.
Teste avant de mettre en prod
Une fois ton heartbeat créé, fais 2 ou 3 pings manuels avec curl depuis ton poste pour vérifier que le monitor passe bien en vert dans le dashboard. Puis attends que la fenêtre + grâce expire sans pinger : tu dois recevoir l'alerte. C'est cinq minutes d'investissement qui valident l'ensemble de la chaîne (réseau, token, intégration alertes).
Garde le token secret
Le token est l'unique identifiant : qui l'a peut faire passer ton monitor pour vivant. Stocke-le dans une variable d'environnement (~/.bashrc, systemd Environment, secret Kubernetes, GitHub Actions secret, AWS Secrets Manager, etc.) et jamais en clair dans Git. Si tu le perds dans un commit public, régénère-le immédiatement dans le dashboard — l'ancien est invalidé.
Un heartbeat par environnement
Crée un monitor distinct pour chaque environnement : staging, prod, europe-west, us-east. Tu sauras immédiatement où ça pète. Mutualiser un seul heartbeat pour plusieurs environnements paraît tentant, mais quand l'alerte arrive à 3 h du matin, tu veux savoir si c'est ton serveur de Toronto ou ton serveur de Paris qui est silencieux.
Surveille aussi les jobs critiques peu fréquents
Le réflexe est de monitorer les crons horaires ou quotidiens. Mais les jobs mensuels ou trimestriels sont souvent les plus critiques (facturation, rapports, archivage légal) et les moins surveillés. Pinguro accepte des intervalles jusqu'à 30 jours : utilise-les. Une facturation mensuelle qui rate, c'est trois mois sans détection si tu ne monitor pas.
Cas d'usage concrets
Voici des situations rencontrées chez nos utilisateurs où le heartbeat a payé le service largement :
- Backup PostgreSQL nocturne :
pg_dump+ push S3 chaque nuit. Heartbeat quotidien, grâce 1 h. Quand un upgrade Postgres a cassé l'authentification du compte de backup, l'alerte est tombée le lendemain matin au lieu du jour où on voulait restaurer. - Synchro Stripe → CRM : import horaire des nouveaux clients. Heartbeat 1 h, grâce 10 min. Quand l'API Stripe a renvoyé un schéma légèrement différent, le script a planté en boucle pendant la nuit. Pris au matin, pas la semaine suivante.
- Job de facturation mensuel : génération des factures le 1er du mois. Heartbeat 30 j, grâce 24 h. La fois où la VM a été éteinte par mégarde après une migration, l'alerte est tombée le 2 au matin au lieu de fin de mois.
- Cleanup des logs hebdomadaire :
find /var/log -mtime +30 -deletechaque dimanche. Heartbeat 7 j. Sans ça, tu découvres le problème quand/varest plein. - Build CI quotidien : rebuild des images Docker de base avec les dernières mises à jour de sécurité. Heartbeat 24 h. Si le runner est en panne pendant un mois, tes images de prod prennent du retard sécurité sans le savoir.
- Health check d'un worker async : ton worker Celery / Sidekiq / BullMQ envoie un ping toutes les 5 minutes. Si le process meurt et que
systemdn'arrive pas à le redémarrer, alerte immédiate.
Pinguro vs alternatives
Le heartbeat n'est pas une invention récente. Voici les principaux services qui le proposent et où Pinguro se positionne.
| Service | Plan gratuit | Langue / support | Status page incluse | Alertes Slack/Telegram |
|---|---|---|---|---|
| Pinguro | 3 monitors | FR / EN | Oui (white-label en Agency) | Oui, sur tous les plans payants |
| Healthchecks.io | 20 checks | EN | Non | Oui |
| Dead Man's Snitch | 1 monitor | EN | Non | Slack uniquement |
| Cronitor | 5 monitors | EN | Oui | Oui |
Healthchecks.io est open-source et excellent si tu veux self-hoster. Dead Man's Snitch est minimaliste, focalisé heartbeat uniquement. Cronitor est complet mais plus cher et anglophone. Pinguro se distingue par la combinaison heartbeat + monitoring HTTP/DNS/TCP + status page + support FR dans un seul outil, à un tarif d'entrée bas (7 €/mois pour le plan Solo, gratuit pour démarrer).
Pour aller plus loin, la documentation détaille toutes les options du heartbeat : docs Pinguro · section Heartbeat / Cron.
Conclusion
Un heartbeat, c'est cinq minutes à mettre en place et zéro entretien ensuite. C'est l'investissement avec le meilleur ratio effort / sérénité du monitoring : tu ajoutes deux caractères (&&) et une URL à ta crontab, et tu sais immédiatement si ton job s'arrête, sans dépendre de la lecture des logs ni de la chance.
Le seul vrai conseil qu'on peut donner : mets-en sur tous tes jobs critiques, pas seulement le plus visible. Les pannes les plus coûteuses sont celles qu'on ne voit pas venir.
Configure ton premier heartbeat en deux minutes
Plan gratuit avec 3 monitors, alertes email, status page publique. Pas de carte bancaire, pas d'engagement.
Créer mon compte gratuit