Aller au contenu principal

Exécutions et supervision

Chaque exécution Nomaflow laisse une trace : une ligne dans ly2_job_runs, une ligne par étape dans ly2_step_runs, chaque ligne de log dans ly2_job_logs. La page Paramètres → Jobs est l'endroit où cette trace est parcourue, filtrée et diffusée en direct.

Cette page décrit le tableau d'historique d'exécution, le tiroir de détail par exécution, la queue de log en direct, le parcours d'abandon et la politique de rétention.


Vue d'ensemble

Exécutions de jobs · 7 derniers jours
Job ▾Statut ▾↻ Rafraîchir
Id d'exécution
Job
Statut
Démarré
Durée
Déclencheur
r-1842
billing-nightly-rebuild
running
02:00:03
2m 14s ⏱
cron
r-1841
crm-hourly-sync
succeeded
02:00:00
0m 38s
cron
r-1840
ad-sync
failed
01:30:00
1m 02s
cron
r-1839
billing-monthly-close
skipped
00:00:00
cron

Le tableau des exécutions

ColonneSource
Id d'exécutionLe run_id unique (par exemple r-1842). Cliquable — ouvre le tiroir de détail.
JobNom du job. La pastille de filtre en haut restreint à un seul job.
StatutPastille colorée — voir statuts ci-dessous.
DémarréQuand l'exécution a commencé (heure locale de l'opérateur). Triable.
DuréeDémarré → terminé (ou « en cours » avec un compteur en direct pour les exécutions en cours).
Déclencheurcron, manual, api, cli — et au survol l'identifiant utilisateur quand le déclenchement est manuel.

Le tableau affiche par défaut les 7 derniers jours, triés par Démarré décroissant. La barre d'outils donne accès à :

  • Une liste déroulante Job — restreindre à un seul job.
  • Une liste déroulante Statut — sélection multiple (running, succeeded, failed, aborted, skipped, partial-success).
  • Un sélecteur de plage de dates — semaine / mois / personnalisée.
  • Un bouton ↻ Rafraîchir — qui rafraîchit aussi automatiquement toutes les 5 s tant qu'au moins une exécution est en running.

Statuts

StatutSignificationFinal ?
runningL'exécution est en cours.Non
succeededChaque étape s'est terminée sans erreur.Oui
failedUne étape a épuisé ses relances et a arrêté le job.Oui
partial-successCertaines étapes ont échoué avec continue_on_error = true ; le job a poursuivi.Oui
abortedUn opérateur a cliqué sur Abandonner ou le timeout_seconds au niveau du job s'est déclenché.Oui
skippedLe job devait se déclencher mais une dépendance / un verrou d'instance unique l'en a empêché.Oui

La colonne reason d'une ligne (visible dans le tiroir de détail) porte la précision — dependency-failed: <name>, single-instance, previous still running, timeout after 1800s, etc.


Le tiroir de détail d'exécution

Cliquer sur une ligne ouvre un tiroir à droite avec trois sections.

En-tête

  • Id d'exécution, nom du job, pastille de statut, horodatages de démarrage / fin, durée, déclencheur.
  • Un bouton Abandonner (visible uniquement quand status = running, uniquement pour les utilisateurs portant job:<name>:abort ou le global job:*).
  • Un bouton Relancer (visible quand le status est final) qui déclenche une nouvelle exécution avec le même instantané de params.

Timeline par étape

Une liste verticale, une entrée par étape dans l'ordre déclaré :

ChampSource
Nom de l'étape + pastille de typeDepuis jobs.toml.
Pastille de statutsucceeded / failed / running / skipped.
DuréeDémarré → terminé (compteur en direct pendant l'exécution).
Instantané d'entréeLa table params / kwargs après toutes les substitutions ${...}. Utile quand la même étape s'est exécutée différemment d'une relance à l'autre.
Instantané de sortieLe résultat de l'étape — rows_affected, row_count, les 100 premières lignes pour SQL, le corps complet de la réponse pour HTTP (tronqué à 100 Kio).
ErreurQuand status = failed, la classe d'exception, le message et la trace pertinente.

Chaque entrée d'étape se déplie en place pour afficher l'entrée / la sortie / l'erreur.

Queue de log en direct

Un panneau défilant sous la timeline diffuse chaque ligne de log de l'exécution — à la fois les événements structurés du framework (step started, step finished, retry triggered) et les messages émis par les appels d'étape python via logging.getLogger(__name__).

Le panneau est diffusé via Socket.IO tant que l'exécution est en cours ; une fois l'exécution terminée, il affiche les lignes de log enregistrées depuis ly2_job_logs. Chaque ligne porte :

  • Un horodatage (précision à la ms dans le fuseau du serveur, rendu dans le fuseau de l'opérateur).
  • Un niveau (DEBUG / INFO / WARNING / ERROR), avec code couleur.
  • Le nom du logger (par exemple billing.invoicing).
  • Le message.

La barre d'outils en haut du panneau donne accès à :

  • Un filtre de niveau — n'afficher que WARNING et ERROR, par exemple.
  • Une zone de recherche — filtre par sous-chaîne sur le message.
  • Un bouton bascule ↻ Suivre — défilement automatique en bas à mesure que les nouvelles lignes arrivent.
  • Un bouton Télécharger — exporte le log complet sous forme de fichier .log.

Abandonner une exécution

Cliquer sur Abandonner dans le tiroir de détail :

  1. Marque l'exécution avec status = aborting en base.
  2. Envoie un asyncio.CancelledError dans la tâche d'étape en cours.
  3. L'appel de l'étape (ou l'exécuteur d'étape du framework) réagit :
    • Les requêtes SQL sont annulées au niveau du pilote (asyncpg / oracledb prennent tous deux en charge l'annulation).
    • Les appels HTTP sont avortés (la connexion sous-jacente est fermée).
    • Les appels d'étape python qui utilisent des points d'attente await voient le CancelledError ; les appels synchrones vont jusqu'au bout de l'itération courante.
  4. L'étape est enregistrée avec status = aborted.
  5. Le job est enregistré avec status = aborted et aucune étape suivante ne s'exécute.

Un appel qui attrape silencieusement CancelledError peut empêcher l'abandon de prendre effet — à éviter dans le code de plugin. Le comportement par défaut (laisser l'exception se propager) est le bon.


Rejouer / Relancer

Le bouton Relancer sur une exécution terminée crée une nouvelle exécution avec :

  • Le même instantané de params.
  • Un nouveau run_id.
  • triggered_by = "user:<operator>" et replay_of = <original run_id>.

Le lien replay_of est visible dans le tiroir de détail sous la forme « ↻ Rejeu de r-1840 ». Cela est utile pour les jobs nocturnes qui ont échoué à cause d'un incident passager et qui ont besoin d'une nouvelle tentative sans attendre le prochain déclenchement cron.


API REST

EndpointBut
GET /admin/jobs/runs?job=<name>&status=<list>&from=&to=&limit=Tableau des exécutions — paginé, filtré.
GET /admin/jobs/runs/<run_id>Une exécution avec la liste complète des étapes et les 1000 dernières lignes de log.
POST /admin/jobs/<name>/runDéclencher une exécution manuelle. Le corps accepte des surcharges de params.
POST /admin/jobs/runs/<run_id>/abortAbandonner une exécution en cours.
POST /admin/jobs/runs/<run_id>/replayRelancer avec les mêmes params.
GET /admin/jobs/runs/<run_id>/logs?level=&follow=Diffuser la queue de log. follow=true bascule sur Socket.IO.

Chaque endpoint demande la permission job:<name> pour le job ciblé (ou job:*). L'endpoint de liste ne retourne que les exécutions des jobs que l'appelant peut voir — filtré automatiquement.


Rétention

Les lignes d'exécution et les lignes de log sont purgées par un job interne (_default/cleanup-job-history) qui se déclenche une fois par jour à 03:00. La politique de rétention :

RéglageDéfautSignification
[jobs] history_days90Les lignes d'exécution plus anciennes que N jours sont supprimées. Les lignes d'étape et de log suivent.
[jobs] history_keep_failedtrueLes exécutions failed / aborted sont conservées au-delà de la fenêtre de rétention — elles alimentent souvent une revue d'incident.
[jobs] log_truncate_kb100Les lignes de log au-delà de N Kio cumulés par exécution sont tronquées (le message de troncature le dit explicitement).

Pour une piste d'audit à long terme, router le flux de log vers votre agrégateur de logs central (Loki, Splunk, Datadog) via LIBERTY_LOG_JSON=1 et considérer l'historique interne du framework comme un cache opérationnel.


Le tableau de bord Technique

L'onglet Paramètres → Technique (soumis à settings:technical) affiche une vue d'ensemble en direct :

PanneauContenu
Exécutions en coursChaque job en status = running, avec le temps écoulé et l'étape courante. Cliquer sur une ligne ouvre le tiroir de détail.
Échecs récentsLes 20 dernières exécutions failed / aborted.
Pouls de l'ordonnanceurDernier déclenchement, prochain déclenchement, profondeur de la file. Utile pour confirmer que l'ordonnanceur est vivant un jour calme.
Statistiques de poolConnexions ouvertes / inactives / utilisées par pool — fait apparaître une saturation de pool qui bloquerait sinon les jobs.

Ce tableau de bord est le premier endroit où regarder quand « un job ne s'est pas exécuté » — le pouls de l'ordonnanceur indique si le framework a même essayé.


Conseils et bonnes pratiques

  • Surveiller le panneau Échecs récents. Un échec isolé par semaine est normal ; une oscillation (un échec par nuit) mérite enquête.
  • Utiliser log.warning() pour « ok mais inhabituel ». Une ligne qui prend 10× plus de temps que d'habitude mérite un WARNING dans le log, pas du silence. Le filtre de niveau dans la queue de log les rend faciles à trouver.
  • Marquer l'exécution avec un identifiant porteur de sens. Une étape python qui logge log.info("billing.invoicing.run period=2026-05 drafts=42 dry_run=False") rend l'historique d'exécution facile à rechercher.
  • Ne pas garder votre unique historique dans le framework. Transférer le log JSON vers votre agrégateur — les incidents côté installation ne devraient pas emporter avec eux la piste d'audit.
  • Abandonner, ne pas tuer. Utiliser le bouton Abandonner plutôt que kill -9 sur le processus du framework — le parcours d'abandon enregistre la raison et préserve l'état partiel pour le post-mortem.

Pour aller plus loin