💻 Développement

dev-cron-job-designer

Conception de tâches planifiées — cron expressions, scheduling patterns, monitoring et idempotence.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- dev-cron-job-designer --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } dev-cron-job-designer -Launch"

🚀 Déjà installé ?

claude "/dev-cron-job-designer"

Ou tapez /dev-cron-job-designer dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

crontâche planifiéescheduled taskcron expressionjob schedulercrontab

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/dev-cron-job-designer ~/.claude/skills/

Payload du plugin : skills/dev-cron-job-designer · source éditable : dev-skills/cron-job-designer

📖 Manuel

Cron Job Designer

Workflow

1. Qualifier le besoin

Avant d'écrire une expression cron, réponds à ces questions :

QuestionImpact
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 'NF{last=$NF} END{print last}') ]

# Chaque heure, décalé de 17 min
17 * * * *

Valideur en ligne : crontab.guru — toujours vérifier avant déploiement.

Syntaxes étendues (systemd, cloud) :

# systemd timer — OnCalendar
OnCalendar=Mon *-*-* 03:17:00

# AWS EventBridge (rate)
rate(1 hour)
# AWS EventBridge (cron, timezone UTC)
cron(17 2 * * ? *)

# Kubernetes CronJob
schedule: "17 2 * * *"

3. Choisir l'outil adapté

ContexteOutil recommandéRemarque
Linux standalonecron / systemd timersystemd > cron : logs journald, retry natif
.NET / ASP.NET CoreHangfire ou Quartz.NETHangfire = dashboard UI intégré
Java / SpringQuartz ou @ScheduledQuartz pour clustering
Node.jsnode-cron ou BullBull si queue nécessaire
PythonCelery Beat ou APSchedulerAPScheduler pour scripts simples
KubernetesCronJob k8sconcurrencyPolicy: Forbid par défaut
AzureAzure Functions Timer ou Logic AppsTimer Trigger = NCRONTAB (6 champs)
AWSEventBridge SchedulerRemplace CloudWatch Events
GCPCloud SchedulerHTTP target ou Pub/Sub

4. Garantir l'idempotence

Patterns selon le cas :

Marqueur en base (le plus simple) :

-- Avant traitement
INSERT INTO job_executions (job_name, run_date, status)
VALUES ('daily-report', CAST(GETDATE() AS DATE), 'running')
-- Si PK violation → déjà en cours, skip

-- Après traitement
UPDATE job_executions SET status = 'done', ended_at = GETDATE()
WHERE job_name = 'daily-report' AND run_date = CAST(GETDATE() AS DATE)

Verrou Redis (multi-instances) :

import redis
r = redis.Redis()
lock = r.set("job:daily-report", "1", nx=True, ex=300)  # TTL = timeout max
if not lock:
    print("Job already running, skip")
    exit(0)
try:
    run_job()
finally:
    r.delete("job:daily-report")

Hangfire (.NET) — DisableConcurrentExecution :

[DisableConcurrentExecution(timeoutInSeconds: 600)]
public void DailyReport() { ... }

5. Gérer les erreurs et les retries

Stratégie par défaut :

# Celery
@app.task(bind=True, max_retries=3, default_retry_delay=60)
def daily_sync(self):
    try:
        sync()
    except TemporaryError as exc:
        raise self.retry(exc=exc, countdown=60 * (2 ** self.request.retries))

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 :

# 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 rondes0 * * * 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