Guides
Administration
Web Scheduler

Web Scheduler

Planifier et automatiser les breakouts CSWeb directement depuis l'interface Web, sans éditer de crontab manuellement. Chaque dictionnaire peut avoir son propre planning et génère ses propres fichiers log.

Nouveauté v2.1 : Le Web Scheduler remplace la configuration manuelle via crontab. Un seul cron système (csweb:scheduler-run) pilote l'ensemble des schedules configurés via l'UI.

Vue d'ensemble

Principe

Le Web Scheduler introduit une table dédiée cspro_breakout_scheduler qui stocke la configuration de planification pour chaque dictionnaire. Un unique crontab système appelle la commande csweb:scheduler-run chaque minute, qui interroge les schedules due et lance les breakouts correspondants.

┌─────────────────────────────────────────────────┐
│              Interface Web (UI)                  │
│                                                  │
│  ┌──────────────────────────────────────────┐    │
│  │  Page Data Settings                      │    │
│  │  ┌────────────────────────────────────┐  │    │
│  │  │  Onglet "Breakout Scheduler"       │  │    │
│  │  │  - Add / Edit / Toggle / Delete    │  │    │
│  │  │  - Cron expression par dict        │  │    │
│  │  │  - Status, Last Run, Next Run      │  │    │
│  │  └────────────────────────────────────┘  │    │
│  └──────────────────────────────────────────┘    │
└──────────────────────┬──────────────────────────┘
                       │ AJAX (REST)
                       v
┌─────────────────────────────────────────────────┐
│  Controller API (5 endpoints)                    │
│  GET /scheduler/schedules                        │
│  POST /scheduler/add                             │
│  PUT /scheduler/update | /scheduler/toggle       │
│  DELETE /scheduler/{id}                          │
└──────────────────────┬──────────────────────────┘

                       v
┌─────────────────────────────────────────────────┐
│  Service BreakoutScheduler.php                   │
│  CRUD + getDueSchedules() + markRun()            │
└──────────────────────┬──────────────────────────┘

                       v
┌─────────────────────────────────────────────────┐
│  Table MySQL : cspro_breakout_scheduler          │
│  (FK vers cspro_dictionaries)                    │
└──────────────────────┬──────────────────────────┘

         * * * * * (crontab)

                       v
┌─────────────────────────────────────────────────┐
│  csweb:scheduler-run (Commande Symfony)          │
│  - Interroge getDueSchedules()                   │
│  - Lance csweb:process-cases-by-dict par dict    │
│  - Écrit logs dans var/logs/breakout/            │
│  - Met à jour last_run, next_run, exit_code      │
└─────────────────────────────────────────────────┘

Avantages par rapport au cron manuel

FonctionnalitéCron ManuelWeb Scheduler
ConfigurationÉditer crontab SSHInterface Web
GranularitéPar commandePar dictionnaire
LogsUn seul fichierUn log par dict + timestamp
MonitoringAucunLast Run, Next Run, Exit Code
Toggle on/offCommenter/décommenterBouton toggle on/off
HistoriqueNonOui (table MySQL)

Configuration Initiale

1. Activer le Crontab Système

Un seul cron suffit pour piloter tous les schedules :

# Éditer crontab
crontab -e
 
# Ajouter cette ligne (exécution chaque minute)
* * * * * php /var/www/html/bin/console csweb:scheduler-run --env=prod >> /var/log/scheduler.log 2>&1

Avec Docker (Intégré)

Le Dockerfile CSWeb inclut déjà un cron intégré qui est démarré automatiquement par le docker-entrypoint.sh. Aucune configuration supplémentaire n'est nécessaire si vous utilisez l'image Docker officielle.

Le cron intégré exécute csweb:scheduler-run chaque minute via /etc/cron.d/csweb-scheduler.

Si vous préférez configurer le cron depuis l'hôte :

# Alternative : crontab sur l'hôte
* * * * * docker compose exec -T csweb php bin/console csweb:scheduler-run --env=prod >> /var/log/scheduler.log 2>&1

2. Migration de la base de données

Si vous upgrader depuis une version antérieure (schema version 7), la migration crée automatiquement la table cspro_breakout_scheduler :

# Accéder à la page d'upgrade
http://your-server/upgrade/upgrade.php

Pour une nouvelle installation, la table est créée automatiquement lors du setup initial.


Utilisation de l'Interface Web

Accéder au Scheduler

  1. Se connecter à CSWeb avec un compte Administrateur
  2. Naviguer vers Settings > Data
  3. Cliquer sur l'onglet Breakout Scheduler

Ajouter un Schedule

  1. Cliquer sur Add Schedule
  2. Sélectionner le dictionnaire (seuls les dictionnaires configurés avec un schema breakout et non encore schedulés sont listés)
  3. Saisir l'expression cron (ex: 0 2 * * * pour tous les jours à 2h)
  4. Cocher Enabled pour activer immédiatement
  5. Cliquer Save

Expressions Cron

Format standard : minute heure jour mois jour_semaine

ExpressionSignification
0 2 * * *Tous les jours à 2h00
0 */6 * * *Toutes les 6 heures
*/30 * * * *Toutes les 30 minutes
0 2 * * 1-5Lundi au vendredi à 2h00
0 0 1 * *Premier jour du mois à minuit
0 2 * * 0Chaque dimanche à 2h00

Tableau de suivi

La table affiche en temps réel :

ColonneDescription
DictionaryNom et label du dictionnaire
Schedule (Cron)Expression cron configurée
StatusBadge Active (vert) ou Inactive (gris)
Last RunDate/heure de la dernière exécution
Next RunProchaine exécution prévue
ActionsToggle, Edit, Run Now, Delete

Actions disponibles

  • Toggle (on/off) : Active ou désactive le schedule sans le supprimer
  • Edit (crayon) : Modifier l'expression cron ou le statut enabled
  • Run Now (play) : Lancer un breakout manuel immédiat pour ce dictionnaire
  • Delete (corbeille) : Supprimer le schedule (avec confirmation via modal Bootstrap)

Logs par Dictionnaire

Chaque exécution génère un fichier log individuel dans var/logs/breakout/ :

var/logs/breakout/
  EVAL_DICT_2026-03-19_02-00-01.log
  EVAL_DICT_2026-03-20_02-00-00.log
  KAIROS_DICT_2026-03-19_02-00-01.log
  KAIROS_DICT_2026-03-20_02-00-00.log

Contenu d'un fichier log

Command: /usr/bin/php /var/www/html/bin/console csweb:process-cases-by-dict EVAL_DICT --env=prod
Started: 2026-03-19_02-00-01
Exit code: 0

--- STDOUT ---
Running blob breakout process.
Processing dictionary: EVAL_DICT- Running threads 0
creating a new blob breakout thread
...

--- STDERR ---

Consulter les logs via l'interface Web

L'onglet Breakout Logs dans la page Data Settings offre un viewer complet :

  • Sidebar dictionnaires : filtrer les logs par dictionnaire avec recherche
  • Table DataTable : tri par date, taille, type (manual/scheduled), pagination
  • Modal viewer : visualisation du contenu du log (thème sombre, numéros de ligne, word wrap, scroll)
  • Actions : télécharger ou supprimer chaque fichier log

Consulter les logs en CLI

# Derniers logs d'un dictionnaire
ls -la var/logs/breakout/EVAL_DICT_*.log
 
# Contenu du dernier log
cat var/logs/breakout/EVAL_DICT_$(ls -t var/logs/breakout/EVAL_DICT_*.log | head -1)
 
# Rechercher erreurs
grep -l "Exit code: [^0]" var/logs/breakout/*.log

Nettoyage automatique des logs

Ajouter un cron de nettoyage :

# Supprimer logs de plus de 30 jours
0 3 * * * find /var/www/html/var/logs/breakout -name "*.log" -mtime +30 -delete

Architecture Technique

Table MySQL

CREATE TABLE `cspro_breakout_scheduler` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `dictionary_id` smallint unsigned NOT NULL,
  `enabled` tinyint(1) NOT NULL DEFAULT 0,
  `cron_expression` varchar(100) NOT NULL DEFAULT '0 2 * * *',
  `last_run` timestamp NULL DEFAULT NULL,
  `next_run` timestamp NULL DEFAULT NULL,
  `last_exit_code` int DEFAULT NULL,
  `last_log_file` varchar(255) DEFAULT NULL,
  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `created_time` timestamp DEFAULT '1971-01-01 00:00:00',
  PRIMARY KEY (`id`),
  UNIQUE KEY `dictionary_id` (`dictionary_id`),
  CONSTRAINT FOREIGN KEY (`dictionary_id`) REFERENCES `cspro_dictionaries`(`id`) ON DELETE CASCADE
);

Note : La contrainte UNIQUE sur dictionary_id garantit un seul schedule par dictionnaire. La contrainte ON DELETE CASCADE supprime automatiquement le schedule si le dictionnaire est supprimé.

Endpoints API

MethodeRouteDescription
GET/scheduler/schedulesListe des schedules + dictionnaires non schedulés
POST/scheduler/addAjouter un schedule
PUT/scheduler/updateModifier cron + enabled
PUT/scheduler/toggleBasculer enabled/disabled
DELETE/scheduler/{id}Supprimer un schedule

Dépendance PHP

Le package dragonmantank/cron-expression (^3.3) est utilisé pour :

  • Valider les expressions cron saisies par l'utilisateur
  • Calculer la prochaine date d'exécution (next_run)

Commande CLI : csweb:scheduler-run

La commande est conçue pour être appelée chaque minute par le crontab système.

php bin/console csweb:scheduler-run --env=prod

Fonctionnement

  1. Acquiert un lock (empêche les exécutions concurrentes via LockableTrait)
  2. Interroge getDueSchedules() : tous les schedules où enabled=1 et next_run <= NOW()
  3. Pour chaque schedule due :
    • Lance csweb:process-cases-by-dict DICT_NAME via Symfony\Process
    • Capture stdout + stderr dans un fichier log {DICT_NAME}_{datetime}.log
    • Appelle markRun() pour mettre à jour last_run, next_run, last_exit_code, last_log_file
  4. Relache le lock

Timeout

Chaque processus de breakout a un timeout de 3600 secondes (1 heure). Si un breakout dépasse ce temps, il est interrompu.


Dépannage

Le scheduler ne s'exécute pas

  1. Vérifier que le crontab est actif :
crontab -l | grep scheduler
  1. Vérifier les logs du scheduler :
tail -f /var/log/scheduler.log
  1. Tester manuellement :
php bin/console csweb:scheduler-run --env=prod -vvv

Schedule ajouté mais "Next Run" vide

Le next_run n'est calculé que si le schedule est enabled. Vérifier que le toggle est sur Active.

Erreur "Invalid cron expression"

L'expression cron doit respecter le format standard à 5 champs. Les extensions comme @daily ou @hourly ne sont pas supportées. Utiliser les équivalents numériques.

Lock : "The scheduler is already running"

Si un breakout précédent est encore en cours, le lock empêche une nouvelle exécution. Attendre la fin du processus ou vérifier :

# Voir si un processus scheduler est actif
ps aux | grep scheduler-run

Bonnes Pratiques

  1. Un seul crontab : Ne pas créer de crons manuels pour les dictionnaires gérés par le scheduler
  2. Expressions prudentes : Éviter */1 * * * * pour des breakouts lourds - préférer des intervalles de 30 min minimum
  3. Nettoyage logs : Configurer un cron de cleanup pour var/logs/breakout/
  4. Monitoring : Consulter régulièrement l'onglet Breakout Logs pour détecter les erreurs

Ressources