L6.3 : une reponse hors enveloppe leve, au lieu de se faire passer pour vide
Les services lisaient `response?.entities || []` sur les reponses de l'API AD
(enveloppe { entities: [...] }, D4). Toute reponse d'une AUTRE forme — corps
vide, objet d'erreur, champ absent — devenait donc un tableau vide,
indistinguable d'une page finale legitime, et etait mise en cache avec un
timestamp valide : un cache vide empoisonne pour tout le TTL, sans le moindre
message. C'est la cause probable du `count: 0` mesure sous rafale, et le mode
d'echec le plus couteux du lot, parce qu'il se lit comme une reponse.
Le contrat est porte par src/services/ad-envelope.js pour les trois sites
(Workflow/GetByApplication, Application/GetAll, <Type>/GetByApplication) :
`{ entities: [...] }`, `[]` reel compris, est rendu tel quel ; toute autre
forme leve. entity-resolver etait deja conforme — il leve deja si
/configuration/applications ou le Metadata ne rendent aucune entite.
Volontairement sans retry ni logique de resilience : le but est de rendre
l'anomalie visible et non persistante. La rattraper la rendrait invisible,
c'est-a-dire exactement le defaut corrige.
--- Verifications (LIMAGRAIN) ---
Vide LEGITIME — search_workflows sur SmartUI (0 workflow, D26) :
search_workflows(SmartUI) : success=true application=SmartUI count=0
isError=false
error : (aucune)
hint : Aucun workflow trouve dans l'application "SmartUI" — c'est la
SEULE interrogee, les autres ne le sont jamais implicitement.
Le specifique client (prefixe CST_) vit dans "CustomApp" : [...]
cache pose ? workflowCachesByApplication =
{"SmartUI":{"cached":true,"count":0,"timestamp":1787665868988,
"age":0,"valid":true}}
stderr : No more workflows to fetch / Successfully cached 0 workflows
Forme SANS `entities` — non declenchable a la demande contre le vrai WMS,
couverte par un test direct (apiService.post substitue, renvoie {}) :
--- workflow-service fetchAllWorkflows("EasyWMS") avec une reponse {} ---
erreur levee : Failed to fetch workflows for application "EasyWMS":
Reponse inattendue de l'API AD sur Workflow/GetByApplication
(application "EasyWMS", offset 0) : un objet vide, au lieu de
l'enveloppe attendue { entities: [...] }. Rien n'a ete mis en cache —
relancez l'appel. Si l'erreur persiste, l'API AD est en defaut [...]
cache : {} (attendu {})
--- workflow-service fetchApplications() avec une reponse {} ---
erreur levee : Reponse inattendue de l'API AD sur Application/GetAll : [...]
cache : {} (attendu {})
--- ad-service getElements("Command") avec une reponse {} ---
erreur levee : Failed to fetch Command for application "EasyWMS": [...]
cache : {} (attendu {})
--- puis une reponse normale : le refetch repart (rien de coince) ---
1 workflow(s), cache : {"EasyWMS":{"cached":true,"count":1,...}}
Cas nominaux du helper (unitaire) : { entities: [] } et { entities: [1,2] }
passent ; {}, null, undefined, [], { error }, "texte" levent tous.
--- Non-regression, rafales rejouees 3 fois ---
L6.1 rafale workflow RUN 1/2/3 : 6/6 a count=44 | fetch=1 joins=5
L6.1 rafale resolver RUN 1/2/3 : 6/6 succes | chargements=1 joins=5 GET=5
L6.1 rafale mixte RUN 1/2/3 : CustomApp@44=3 EasyWMS@50=3 |
fetch=2 joins=4
L6.2 bascule RUN 1/2/3 : caches peuples : 0 (attendu 0)
sequentiel nominal count=50 puis count=50 | fetch=1 cached=1 joins=0
Baseline finale : tools/list 23, resources/list 6 ; npm test 4/4, exit 0.
ROADMAP : lot 6 retire. Le point ouvert « bascule de profil concurrente aux
appels en vol » reste — D27 borne les chargements paresseux, pas le routage
d'une requete deja partie.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+3
-25
@@ -82,30 +82,6 @@ plus riche que `/AD/api/Application/GetAll`), `GET /healthcheck?tenantCode=` et
|
||||
|
||||
---
|
||||
|
||||
## Lot 6 — Chargements paresseux sous concurrence
|
||||
|
||||
Mesuré le 25/08/2026 (révisions des lots 2 et 5) : sans aucune bascule de
|
||||
profil, une rafale d'appels concurrents pendant un chargement paresseux
|
||||
produit des résultats faux en silence — `search_workflows("CST_",
|
||||
application: "CustomApp")` a répondu `count: 0` (contre 44 en séquentiel), et
|
||||
une rafale au lot 2 a déclenché **6 chargements Metadata complets en
|
||||
parallèle** (6 × `[EntityResolver] Cache expired or empty, fetching…`).
|
||||
Rejoués en séquentiel, les mêmes appels sont corrects.
|
||||
|
||||
Trois défauts structurels dans les services à cache (`workflow-service`,
|
||||
`ad-service`, `entity-resolver`) :
|
||||
|
||||
### L6.3 — Ne pas encaisser un vide anormal
|
||||
|
||||
`fetchAllWorkflows` fait `response?.entities || []` puis met en cache le
|
||||
résultat même vide, avec un timestamp valide : toute réponse transitoirement
|
||||
anormale (forme inattendue sous concurrence) devient un **cache vide
|
||||
empoisonné pour tout le TTL** — cause probable du `count: 0` mesuré. Une
|
||||
forme sans `entities` doit lever ; un `entities: []` réel reste cachable
|
||||
(des applications légitimement vides existent, ex. `SmartUI`).
|
||||
|
||||
---
|
||||
|
||||
## Écarté
|
||||
|
||||
| Proposition | Raison |
|
||||
@@ -135,7 +111,9 @@ forme sans `entities` doit lever ; un `entities: []` réel reste cachable
|
||||
singleton d'état global (D8). À traiter si un cas réel de mélange de profils
|
||||
est observé (piste : sérialiser les `tools/call` ou figer le profil résolu au
|
||||
début de chaque appel). La manifestation « caches » de la même concurrence
|
||||
est traitée par le **lot 6** ci-dessus.
|
||||
est **traitée** (D27 : single-flight par clé, garde de génération) ; celle-ci
|
||||
ne l'est pas — D27 borne les chargements paresseux, pas le routage d'une
|
||||
requête déjà partie.
|
||||
- **`select_expression`** : les projections via le paramètre `Select` provoquent
|
||||
des erreurs de compilation côté serveur (D13). Irritant principal restant.
|
||||
- **Déploiement SSH sur la VM** : l'exécutable est validé, la configuration SSH
|
||||
|
||||
Reference in New Issue
Block a user