[136] Planifier la transformation vers la zone argent #143

Merged
lenaic merged 2 commits from lenaic/136-planifier-silver into develop 2026-09-04 08:59:04 +00:00
Owner

Ferme #136. À fusionner après la #142, dont l'entrée de crontab suppose la
correction de la grille.

Le constat

Le seau silver est à 0 objet alors que le code du #34 est fusionné et
déployé, et que bronze en contient 9090. Le job n'est appelé par rien.

Vérifié sur le serveur : crontabs de root, deploy et lenaic,
/etc/crontab, /etc/cron.d, /etc/cron.hourly, /etc/cron.daily, minuteries
systemd et unités nommées. Seules les deux lignes du collecteur existent.

Et une ligne posée en l'état aurait échoué à chaque passage, pour deux
raisons qui ne se voient pas en lisant la liste des tâches.

1. Le lanceur ignorait le python du venv

silver-daily.sh faisait exec python3, là où les lanceurs du collecteur font
exec "${ENERVISION_PYTHON:-python3}". Sur le serveur :

$ python3 -c "import duckdb"
ModuleNotFoundError: No module named 'duckdb'

C'est le mode de panne relevé en relecture de la #114 pour le collecteur,
reproduit à l'identique dans l'ETL.

Le lanceur vérifie maintenant ses dépendances avant de partir et sort en 3 avec
un message qui nomme la cause. Les deux dépendances sont nommées explicitement
plutôt que remplacées par un import etl.silver.job plus général
, et c'est
délibéré : entrepot.py importe minio et duckdb tardivement, pour que les tests
unitaires tournent sans le SDK. Importer le module réussit donc sans eux. J'ai
écrit la version générale d'abord, et le banc local l'a montrée inopérante,
retombant sur la trace brute avec le code 1.

2. Le rôle supposait le service

La tâche de stat comme la ligne de crontab construisaient le chemin avec
services/collector/bin/ en dur. Juste tant qu'il n'y avait que des collecteurs,
faux dès que l'ETL doit être planifié : son lanceur vit dans services/etl/bin.

Le chemin vient désormais du champ service de la tâche, et collector_taches
devient taches_planifiees : la liste ne décrit plus le seul collecteur.

3. L'entrée silver

Minute 0 de chaque heure, sur la journée courante, journal dans
/var/log/enervision/silver.log, déjà couvert par la rotation *.log en place.
Le rôle ne pose la ligne que si le lanceur existe dans le dépôt.

Éprouvé en local, pas seulement lu

Le banc du rôle gagne un contrôle sur ce chemin, vert sur le rôle corrigé,
rouge sur le chemin en dur réintroduit
:

TASK [Le chemin du lanceur vient de la tâche, pas d'un service supposé]
fatal: FAILED! => {"assertion": "'item.service' in bloc_stat"}

Aucun linter ne voit un chemin littéral qui se trouve être le bon pour deux
entrées sur trois, et c'est exactement ce que ce banc existe pour attraper.

yamllint propre, ansible-lint à 0 défaut en profil production,
site.yml --syntax-check passant, ansible-playbook tests/ci/test-role-app.yml
à ok=10 failed=0. Le préflight du lanceur éprouvé dans les deux sens, code 3
sans les dépendances et silencieux avec.

Le manuel

docs/runbooks/etl.md dit comment vérifier que ça tourne, comment lire un
refus du garde-fou sans le confondre avec une panne
, comment rejouer une
journée et comment éprouver une règle sans toucher à la production. C'est la
confusion qui nous a coûté du temps ce matin.

Risque

Faible. Le pire cas est une tâche horaire qui échoue et remplit silver.log,
déjà en rotation. Retour arrière : passer l'entrée à state: absent dans
taches_planifiees et rejouer le rôle, sans toucher aux deux du collecteur.

Ferme #136. **À fusionner après la #142**, dont l'entrée de crontab suppose la correction de la grille. ## Le constat Le seau `silver` est à **0 objet** alors que le code du #34 est fusionné et déployé, et que bronze en contient 9090. Le job n'est appelé par rien. Vérifié sur le serveur : crontabs de `root`, `deploy` et `lenaic`, `/etc/crontab`, `/etc/cron.d`, `/etc/cron.hourly`, `/etc/cron.daily`, minuteries systemd et unités nommées. Seules les deux lignes du collecteur existent. **Et une ligne posée en l'état aurait échoué à chaque passage**, pour deux raisons qui ne se voient pas en lisant la liste des tâches. ## 1. Le lanceur ignorait le python du venv `silver-daily.sh` faisait `exec python3`, là où les lanceurs du collecteur font `exec "${ENERVISION_PYTHON:-python3}"`. Sur le serveur : ``` $ python3 -c "import duckdb" ModuleNotFoundError: No module named 'duckdb' ``` C'est le mode de panne relevé en relecture de la #114 pour le collecteur, reproduit à l'identique dans l'ETL. Le lanceur vérifie maintenant ses dépendances avant de partir et sort en 3 avec un message qui nomme la cause. **Les deux dépendances sont nommées explicitement plutôt que remplacées par un `import etl.silver.job` plus général**, et c'est délibéré : `entrepot.py` importe minio et duckdb tardivement, pour que les tests unitaires tournent sans le SDK. Importer le module réussit donc sans eux. J'ai écrit la version générale d'abord, et le banc local l'a montrée inopérante, retombant sur la trace brute avec le code 1. ## 2. Le rôle supposait le service La tâche de `stat` comme la ligne de crontab construisaient le chemin avec `services/collector/bin/` en dur. Juste tant qu'il n'y avait que des collecteurs, faux dès que l'ETL doit être planifié : son lanceur vit dans `services/etl/bin`. Le chemin vient désormais du champ `service` de la tâche, et `collector_taches` devient `taches_planifiees` : la liste ne décrit plus le seul collecteur. ## 3. L'entrée silver Minute 0 de chaque heure, sur la journée courante, journal dans `/var/log/enervision/silver.log`, déjà couvert par la rotation `*.log` en place. Le rôle ne pose la ligne que si le lanceur existe dans le dépôt. ## Éprouvé en local, pas seulement lu Le banc du rôle gagne un contrôle sur ce chemin, **vert sur le rôle corrigé, rouge sur le chemin en dur réintroduit** : ``` TASK [Le chemin du lanceur vient de la tâche, pas d'un service supposé] fatal: FAILED! => {"assertion": "'item.service' in bloc_stat"} ``` Aucun linter ne voit un chemin littéral qui se trouve être le bon pour deux entrées sur trois, et c'est exactement ce que ce banc existe pour attraper. `yamllint` propre, `ansible-lint` à 0 défaut en profil production, `site.yml --syntax-check` passant, `ansible-playbook tests/ci/test-role-app.yml` à `ok=10 failed=0`. Le préflight du lanceur éprouvé dans les deux sens, code 3 sans les dépendances et silencieux avec. ## Le manuel `docs/runbooks/etl.md` dit comment vérifier que ça tourne, **comment lire un refus du garde-fou sans le confondre avec une panne**, comment rejouer une journée et comment éprouver une règle sans toucher à la production. C'est la confusion qui nous a coûté du temps ce matin. ## Risque Faible. Le pire cas est une tâche horaire qui échoue et remplit `silver.log`, déjà en rotation. Retour arrière : passer l'entrée à `state: absent` dans `taches_planifiees` et rejouer le rôle, sans toucher aux deux du collecteur.
lenaic self-assigned this 2026-09-04 08:08:49 +00:00
infra: planifier la transformation vers la zone argent
Some checks failed
Intégration / Python — qualité, tests et dépendances (pull_request) Successful in 2m6s
Intégration / Tableau de bord — dépendances, tests et construction (pull_request) Failing after 2m16s
Intégration / Contrôles statiques du dépôt (pull_request) Successful in 4s
Intégration / Aucun secret commité (pull_request) Successful in 3s
Infra Ansible / Playbooks Ansible valides (pull_request) Successful in 58s
25363f2350
Le seau `silver` est à zéro objet alors que le code du #34 est fusionné et
déployé, et que bronze en contient 9090. Le job n'était appelé par rien, et une
ligne de crontab posée en l'état aurait échoué à chaque passage.

Trois obstacles, dont deux invisibles tant qu'on ne les cherche pas.

`silver-daily.sh` faisait `exec python3`, là où les lanceurs du collecteur font
`exec "${ENERVISION_PYTHON:-python3}"`. Le python du système n'a pas duckdb : la
tâche serait sortie en ModuleNotFoundError toutes les heures, le même mode de
panne que celui relevé par Olivier en relecture de la #114. Le lanceur vérifie
maintenant ses dépendances avant de partir et sort en 3 avec un message qui
nomme la cause, plutôt qu'une trace d'import au milieu du journal.

La tâche de planification construisait le chemin avec `services/collector/bin/`
en dur, dans la tâche de stat comme dans la ligne de crontab. C'était juste tant
qu'il n'y avait que des collecteurs. Le chemin vient désormais du champ
`service` de la tâche, et `collector_taches` devient `taches_planifiees` : la
liste ne décrit plus le seul collecteur.

L'entrée silver tourne à la minute 0 de chaque heure, sur la journée courante.
Elle suppose le #135, sans lequel la passe refuserait d'écrire avant 17 h.

Le banc d'essai du rôle gagne un contrôle sur ce chemin, éprouvé dans les deux
sens : vert sur le rôle corrigé, rouge sur le chemin en dur réintroduit. Aucun
linter ne voit un chemin littéral qui se trouve être le bon pour deux entrées
sur trois, et c'est exactement ce que ce banc existe pour attraper.

`docs/runbooks/etl.md` dit comment vérifier que ça tourne, comment lire un refus
du garde-fou sans le confondre avec une panne, et comment rejouer une journée.

Ferme #136
marvin approved these changes 2026-09-04 08:20:43 +00:00
Merge branch 'develop' into lenaic/136-planifier-silver
Some checks failed
Intégration / Python — qualité, tests et dépendances (pull_request) Successful in 2m6s
Intégration / Contrôles statiques du dépôt (pull_request) Successful in 4s
Intégration / Aucun secret commité (pull_request) Successful in 2s
Infra Ansible / Playbooks Ansible valides (pull_request) Successful in 1m9s
Intégration / Tableau de bord — dépendances, tests et construction (pull_request) Has been cancelled
de087a6663
gabriel approved these changes 2026-09-04 08:51:14 +00:00
lenaic merged commit d043bbe97f into develop 2026-09-04 08:59:04 +00:00
lenaic deleted branch lenaic/136-planifier-silver 2026-09-04 08:59:04 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
g2/enervision!143
No description provided.