Conception de tâches planifiées — cron expressions, scheduling patterns, monitoring et idempotence. Se déclenche avec "cron", "tâche planifiée", "scheduled task", "cron expression", "job scheduler", "crontab". Also triggers on "schedule a job", "recurring task design".
Conception de tâches planifiées — cron expressions, scheduling patterns, monitoring et idempotence. Se déclenche avec "cron", "tâche planifiée", "scheduled task", "cron expression", "job scheduler", "crontab". Also triggers on "schedule a job", "recurring task design".
Cron Job Designer
Workflow
1. Qualifier le besoin
Avant d'écrire une expression cron, réponds à ces questions :
Question
Impact
Fenêtre d'exécution stricte (ex. avant 6h) ?
Timeout max à fixer
Idempotent par nature ou à construire ?
Stratégie de verrou
Exécution multi-instances (k8s, cloud) ?
Leader election
Dépendance externe (API, DB, SFTP) ?
Circuit breaker + retry
Fréquence < 1 min ?
Cron inadapté → message queue
2. Concevoir l'expression cron
Syntaxe standard (5 champs) :
┌── minute (0-59)
│ ┌── heure (0-23)
│ │ ┌── jour du mois (1-31)
│ │ │ ┌── mois (1-12)
│ │ │ │ ┌── jour de la semaine (0-6, 0=dim)
│ │ │ │ │
* * * * *
Exemples copiables :
# Tous les jours à 2h07 (décalé pour éviter 2h00)
7 2 * * *
# Toutes les 15 min en heures ouvrables (8h-18h, lun-ven)
*/15 8-18 * * 1-5
# Premier lundi du mois à 3h30
30 3 * * 1 [ $(date +\%d) -le 7 ] && /path/to/script.sh
# Alternative avec Quartz/Hangfire : "0 30 3 ? * 2#1"# Dernier jour du mois à minuit (approximation)
55 23 28-31 * * [ $(date +\%d) -eq $(cal | awk ) ]
17 * * * *
'NF{last=$NF} END{print last}'
# Chaque heure, décalé de 17 min
Valideur en ligne : crontab.guru — toujours vérifier avant déploiement.
-- Avant traitementINSERT INTO job_executions (job_name, run_date, status)
VALUES ('daily-report', CAST(GETDATE() ASDATE), 'running')
-- Si PK violation → déjà en cours, skip-- Après traitementUPDATE job_executions SET status ='done', ended_at = GETDATE()
WHERE job_name ='daily-report'AND run_date =CAST(GETDATE() ASDATE)
Décision circuit breaker : si le job dépend d'une API externe, ne pas reessayer
indéfiniment — ouvrir le circuit après 3 échecs consécutifs et attendre 10 min.
6. Configurer le monitoring
Métriques minimales à collecter :
job_started_at, job_ended_at, durée d'exécution
Statut : success / failed / skipped
Nombre d'enregistrements traités
# Pattern de log structuré (JSON)
{"event":"job_start","job":"daily-report","ts":"2026-06-24T02:17:00Z"}
{"event":"job_end","job":"daily-report","ts":"2026-06-24T02:19:43Z","status":"success","records":1542,"duration_s":163}
Healthchecks.io / Cronitor : ping HTTP à la fin de chaque exécution réussie.
Si le ping n'arrive pas dans la fenêtre attendue → alerte automatique.
# Ping de fin (shell)
curl -fsS --retry 3 https://hc-ping.com/UUID > /dev/null
Alerte sur exécution manquée : configurer un timeout = période × 1.5 (ex. job
quotidien → alerte si pas de ping en 36h).
7. Mécanisme de déclenchement manuel
Chaque job doit pouvoir s'exécuter hors du scheduler :
# Linux : wrapper avec flag
./scripts/daily-report.sh --force
# Hangfire : API ou dashboard
BackgroundJob.Enqueue(() => new DailyReportJob().Run());
# k8s : déclencher manuellement un CronJob
kubectl create job daily-report-manual --from=cronjob/daily-report
Anti-patterns et pièges
Exécution aux heures rondes — 0 * * * * au lieu de 17 * * * * :
toutes les instances cloud redémarrent souvent en début d'heure → pics de charge.
Pas de timeout — un job bloqué occupe un slot indéfiniment et empêche le
suivant de s'exécuter. Toujours fixer activeDeadlineSeconds (k8s) ou un
CancellationToken avec timeout.
Skip silencieux — si concurrencyPolicy: Forbid et que le job précédent
tourne encore, k8s skip sans alerte. Monitorer kube_cronjob_missed_schedule_time.
Tâche trop fine — des milliers de micro-crons pour traiter chaque ligne
indépendamment. Préférer un batch unique qui parcourt les lignes en boucle.
Dépendance à l'heure locale — cron tourne en UTC sur la plupart des serveurs.
Un job "à 8h du matin" en heure d'été Europe/Paris → 6 * * * * en UTC.
Documenter la timezone et utiliser TZ=Europe/Paris dans crontab ou le scheduler.
Accumulation de jobs en attente — si un job rate et que les retries s'accumulent,
la queue explose. Mettre un max_retries + TTL sur chaque job.
Bonnes pratiques 2026
Préférer systemd timers à cron sur Linux : logs journald, OnFailure=, RandomizedDelaySec intégré.
En environnement cloud-native, ne pas dockeriser un cron — utiliser un CronJob k8s ou le scheduler cloud natif.
Stocker les expressions cron dans le code (Infrastructure as Code), pas dans une UI manuelle.
Tester les expressions avec --dry-run ou en environnement de staging avec une fréquence augmentée temporairement.
Documenter chaque job : expression cron, timezone, durée attendue, propriétaire, impact si manqué.
Communication Rules — MANDATORY
Ultra-concise. No filler, no preamble, no pleasantries.
Never say "happy to help", "sure!", "great question", "let me", or similar.
Tool first, talk second. Act before explaining.
Result first. Lead with outcome, not process.
Stop when done. No summary, no recap, no trailing commentary.