fix(collecteur) : la requête se lit jusqu'à la fin de ses en-têtes (RST sur le 132) #1820

Merged
foXaCe merged 1 commit from fix/collecteur-requete-decoupee into main 2026-10-17 13:51:45 +02:00
Collaborator

Le symptôme

Le service du 132 journalisait, en boucle :

2026-10-17T11:36:53+00:00 ERREUR-COLLECTEUR source=collecteur url=http://192.168.1.142:8798/processus.json raison=lecture : Connection reset by peer (os error 104)
2026-10-17T11:38:13+00:00 ERREUR-COLLECTEUR source=collecteur url=http://192.168.1.142:8798/processus.json raison=envoi : Broken pipe (os error 32)

43 lignes en 25 min, soit une requête sur trois en échec, alors que le collecteur répond en 0,00 s :

  • requête rejouée à la main depuis le 132 : 6/6 OK, 31 182 octets ;
  • dans le sandbox du service (systemd-run avec ses propriétés) : 13/13 OK à 10 s d'intervalle ;
  • en rafale concurrente (8 fils × 3 vagues) : 24/24 OK.

Le collecteur n'était donc ni éteint, ni lent, ni saturé.

La cause

servir (collecteur) lisait la requête d'un seul read de 2 048 octets :

let mut b = [0u8; 2048];
let n = s.read(&mut b).unwrap_or(0);
let req = String::from_utf8_lossy(&b[..n]);

Un GET de 74 octets tient en un paquet, mais TCP est libre de le découper. Quand ça arrivait, le collecteur répondait sur un chemin tronqué (/proces), puis fermait le socket pendant que le service écrivait encore sa requête — d'où Broken pipe à l'envoi et Connection reset by peer à la lecture. Intermittent par nature : d'où les mesures ci-dessus qui ne le reproduisent jamais sur un petit échantillon.

Le faux worker du banc de l'orchestrateur avait reçu exactement ce correctif (cad5ef01, « le faux worker lit la requête jusqu'à la fin des en-têtes ») ; le collecteur réel, lui, ne l'avait pas eu.

Le correctif

La lecture passe dans collecteur::http::lire_requete : jusqu'à \r\n\r\n, la fin du flux, ou une borne de 8 Kio (ce serveur ne sert que des GET sans corps). Avec son banc (collecteur/tests/http.rs) :

  • découpage en paquets de 7 octets puis de 1 octet : le chemin survit ;
  • un seul paquet : même résultat ;
  • arrêt à la fin des en-têtes (le client garde la connexion ouverte : on ne l'attend pas) ;
  • borne : une requête sans fin s'arrête à 8 Kio.

Mesuré : cargo test -p collecteur --locked, 65 tests, 0 échec.

Reste à faire après la fusion

Le binaire du collecteur tourne sur le LXC 130 : il faudra le reposer (deployer.sh, partie collecteur) pour que le 132 cesse de journaliser ces échecs.

## Le symptôme Le service du 132 journalisait, en boucle : ``` 2026-10-17T11:36:53+00:00 ERREUR-COLLECTEUR source=collecteur url=http://192.168.1.142:8798/processus.json raison=lecture : Connection reset by peer (os error 104) 2026-10-17T11:38:13+00:00 ERREUR-COLLECTEUR source=collecteur url=http://192.168.1.142:8798/processus.json raison=envoi : Broken pipe (os error 32) ``` 43 lignes en 25 min, soit **une requête sur trois en échec**, alors que le collecteur répond en 0,00 s : - requête rejouée à la main depuis le 132 : 6/6 OK, 31 182 octets ; - **dans le sandbox du service** (`systemd-run` avec ses propriétés) : 13/13 OK à 10 s d'intervalle ; - en rafale concurrente (8 fils × 3 vagues) : 24/24 OK. Le collecteur n'était donc ni éteint, ni lent, ni saturé. ## La cause `servir` (collecteur) lisait la requête d'un **seul `read` de 2 048 octets** : ```rust let mut b = [0u8; 2048]; let n = s.read(&mut b).unwrap_or(0); let req = String::from_utf8_lossy(&b[..n]); ``` Un `GET` de 74 octets tient en un paquet, mais **TCP est libre de le découper**. Quand ça arrivait, le collecteur répondait sur un chemin tronqué (`/proces`), puis fermait le socket pendant que le service écrivait encore sa requête — d'où `Broken pipe` à l'envoi et `Connection reset by peer` à la lecture. Intermittent par nature : d'où les mesures ci-dessus qui ne le reproduisent jamais sur un petit échantillon. Le faux worker du banc de l'orchestrateur avait reçu exactement ce correctif (`cad5ef01`, « le faux worker lit la requête jusqu'à la fin des en-têtes ») ; le collecteur réel, lui, ne l'avait pas eu. ## Le correctif La lecture passe dans `collecteur::http::lire_requete` : jusqu'à `\r\n\r\n`, la fin du flux, ou une borne de 8 Kio (ce serveur ne sert que des `GET` sans corps). Avec son banc (`collecteur/tests/http.rs`) : - découpage en paquets de **7 octets** puis de **1 octet** : le chemin survit ; - un seul paquet : même résultat ; - arrêt à la fin des en-têtes (le client garde la connexion ouverte : on ne l'attend pas) ; - borne : une requête sans fin s'arrête à 8 Kio. Mesuré : `cargo test -p collecteur --locked`, **65 tests, 0 échec**. ## Reste à faire après la fusion Le binaire du collecteur tourne sur le **LXC 130** : il faudra le reposer (`deployer.sh`, partie collecteur) pour que le 132 cesse de journaliser ces échecs.
fix(collecteur): la requête se lit jusqu'à la fin de ses en-têtes
All checks were successful
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (pull_request) Successful in 1m58s
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (pull_request) Successful in 7m19s
58ab162afe
Le service du 132 journalisait « lecture : Connection reset by peer » puis « envoi : Broken pipe »
une fois sur trois en interrogeant GET /processus.json (43 lignes en 25 min, mesuré le 2026-10-17),
alors que la même requête rejouée à la main réussissait toujours — y compris dans le sandbox du
service, en rafale et à huit connexions simultanées.

La cause est dans servir : la requête était lue d'un SEUL read de 2 048 octets. Un GET de 74 octets
tient en un paquet, mais TCP est libre de le découper ; le collecteur répondait alors sur un chemin
tronqué (/proces) puis fermait le socket pendant que le client écrivait encore — d'où le RST. Le
faux worker du banc de l'orchestrateur avait reçu le même correctif (cad5ef01) ; le collecteur, lui,
ne l'avait pas eu.

La lecture passe dans collecteur::http::lire_requete — jusqu'à \r\n\r\n, la fin du flux, ou une
borne de 8 Kio — avec son banc : découpage en paquets de 7 puis de 1 octet, arrêt à la fin des
en-têtes, borne. Mesuré : cargo test -p collecteur, 65 tests verts.

Le binaire tourne sur le LXC 130 : à reposer après la fusion pour que le 132 cesse de journaliser
ces échecs.
foXaCe merged commit d4bb8ba065 into main 2026-10-17 13:51:45 +02:00
foXaCe deleted branch fix/collecteur-requete-decoupee 2026-10-17 13:51:45 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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
foXaCe/studio!1820
No description provided.