← retour aux snippets

cron: job robuste avec logs et lock

Programmer un job fiable avec PATH, timezone, timeout, verrouillage et logs quotidiens.

bash système #cron#crontab#logs#lock

objectif

Planifier un job cron sûr: environnement propre, exécution unique (lock), délai maximum (timeout) et logs quotidiens avec rétention.

code minimal

# crontab utilisateur (crontab -e)
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
CRON_TZ=UTC
MAILTO=""

# toutes les 5 min: healthcheck api.data.pm avec lock + timeout + log daté
*/5 * * * * flock -n /tmp/health-data.pm.lock \
  bash -lc 'set -Eeuo pipefail; log="/var/log/data.pm/health-$(date -u +\%Y-\%m-\%d).log"; mkdir -p /var/log/data.pm; timeout 15s curl -fsS https://api.data.pm/health | jq -c . >> "$log" 2>&1'

utilisation

# 1) script robuste dédié (recommandé): /usr/local/bin/health-data-pm.sh
sudo install -m 0755 /dev/stdin /usr/local/bin/health-data-pm.sh <<'SH'
#!/usr/bin/env bash
set -Eeuo pipefail
log_dir="/var/log/data.pm"
log="$log_dir/health-$(date -u +%Y-%m-%d).log"
mkdir -p "$log_dir"

# mesure + contenu json (code HTTP, ttfb, total)
code="$(
  curl -sS -o /tmp/resp.$$ \
    -w '%{http_code}\t%{time_starttransfer}\t%{time_total}' \
    https://api.data.pm/health
)"
http="$(cut -f1 <<<"$code")"
ttfb="$(cut -f2 <<<"$code")"
total="$(cut -f3 <<<"$code")"
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"

printf '%s %s http=%s ttfb=%.3fs total=%.3fs ' "$ts" "api.data.pm" "$http" "$ttfb" "$total" >> "$log"
jq -c . </tmp/resp.$$ >> "$log" || cat /tmp/resp.$$ >> "$log"
rm -f /tmp/resp.$$

# rétention: garder 7 jours
find "$log_dir" -type f -name 'health-*.log' -mtime +7 -delete
SH

# 2) crontab root (accès à /var/log); une seule exécution à la fois + délai 20s
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
CRON_TZ=UTC
MAILTO=""
*/5 * * * * flock -n /tmp/health-data.pm.lock timeout 20s /usr/local/bin/health-data-pm.sh

# 3) job de sauvegarde nocturne (exemple data.pm -> /srv/backup) avec logs
0 2 * * * flock -n /tmp/backup-data.pm.lock \
  bash -lc 'set -Eeuo pipefail; d=/srv/backup/data.pm; mkdir -p "$d"; log="/var/log/data.pm/backup-$(date -u +\%Y-\%m-\%d).log"; \
  rsync -a --delete --human-readable --info=stats2,progress2 /srv/data.pm/ "$d/" >> "$log" 2>&1'

variante(s) utile(s)

# /etc/cron.d (format système, champ utilisateur requis)
# fichier: /etc/cron.d/data-pm-health
# CRON_TZ=UTC
# SHELL=/bin/bash
# PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
*/5 * * * * root flock -n /tmp/health-data.pm.lock timeout 15s /usr/local/bin/health-data-pm.sh

# exécuter au démarrage puis toutes les 10 min
@reboot flock -n /tmp/boot-data.pm.lock timeout 60s /usr/local/bin/health-data-pm.sh
*/10 * * * * flock -n /tmp/health-data.pm.lock timeout 15s /usr/local/bin/health-data-pm.sh

# limiter l'impact CPU/IO (Linux)
*/5 * * * * nice -n 10 ionice -c3 flock -n /tmp/health-data.pm.lock timeout 15s /usr/local/bin/health-data-pm.sh

# avertir si code HTTP != 200 (mail local ou webhook)
*/5 * * * * bash -lc 'set -Eeuo pipefail; c=$(curl -fsS -o /dev/null -w "%{http_code}" https://api.data.pm/health || echo 000); [ "$c" = "200" ] || logger -t data.pm "health HTTP=$c"'

notes

  • définissez toujours SHELL, PATH, CRON_TZ et MAILTO en tête de crontab.
  • utilisez flock pour empêcher les chevauchements et timeout pour borner la durée.
  • écrivez des logs quotidiens datés et appliquez une rétention simple avec find -mtime.
  • mettez les scripts sous /usr/local/bin avec set -Eeuo pipefail et chemins absolus.
  • pour surveiller les logs, combinez avec journalctl ou tail -F /var/log/data.pm/*.log.