# Tâche 5 — Automatisations planifiées (scheduler croner) > Statut : **implémenté** (2026-06-06). tsc 0 · 113 tests · build OK · boot OK. > Réf. : `tache5.md §4` (automatisations backend), `validation_tache5.md`. ## Périmètre livré (1re tranche tâche 5) Planificateur piloté par la BDD : exécuter `apt_update_analyze` / `machine_metrics_simple` / `docker_scan` sur un périmètre de machines à heure fixe (cron), avec concurrence + verrou. - **Table `schedules`** (migration 0007) : name, enabled, cron, timezone, scope_json, actions_json, concurrency, notify_on_json, last_run_at, last_status. - **`server/services/scheduler.ts`** : - CRUD (validation cron via `new Cron()` à la création/maj). - `runSchedule` : résout le scope (`all` ou liste), exécute les actions par machine avec **pool de concurrence** + **verrou par machine** (in-process Set, évite 2 actions simultanées), met à jour last_run_at/last_status, `recordEvent` sur échec. - mapping actions → `refreshMachine` / `collectMetrics` / `scanDockerStacks`. - `reloadSchedules` : (ré)enregistre les crons actifs via croner (timezone par schedule). - **`worker.ts`** : `startWorker` = `reloadSchedules()` (remplace le refresh 30 min en dur). - **Routes** `/api/schedules` : list / create / get / patch / delete / `:id/run` (lancement immédiat). - **UI** : onglet Paramètres « Automatisations » — liste (cron, actions, actif, dernier run), activer/désactiver, lancer maintenant, supprimer, et formulaire de création (nom, cron, cases d'actions, toutes machines). ## Vérifié CRUD via API, cron invalide rejeté proprement (message croner), init scheduler sans erreur, migration 0007 appliquée. Verrou empêche les exécutions concurrentes sur une même machine. ## Reste tâche 5 (backlog) Notifications (`notifyOn`), tags de scope, retries persistants, extraction structurée des **messages importants** (E:/W:/dépréciations → `important_messages` + tuile), timeline d'événements machine, politiques de rétention. (pg-boss = piste future si jobs distribués.)