v0.1.2-pre.004-fix.001
This commit is contained in:
157
deltas/0.1.2/pre.004-fix.001.md
Normal file
157
deltas/0.1.2/pre.004-fix.001.md
Normal file
@@ -0,0 +1,157 @@
|
||||
<!-- file: deltas/0.1.2/pre.004-fix.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.1.2-pre.004-fix.001
|
||||
|
||||
## Base requise
|
||||
|
||||
Livraison précédente :
|
||||
|
||||
```text
|
||||
0.1.2-pre.004
|
||||
```
|
||||
|
||||
La base porte :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.2-pre.4"
|
||||
Cargo.toml header version = 31
|
||||
```
|
||||
|
||||
## Validations remontées
|
||||
|
||||
Les validations utilisateur de `pre.004` sont :
|
||||
|
||||
```text
|
||||
cargo fmt --all OK
|
||||
cargo check --workspace OK
|
||||
cargo clippy --workspace --all-targets OK
|
||||
cargo test --workspace ECHEC
|
||||
cargo tree -p ksp-logging-lib OK
|
||||
cargo tree -p ksp-logging-lib -d OK — aucun doublon
|
||||
cargo tree -p ksp-logging-lib -e features inspecté
|
||||
```
|
||||
|
||||
Tous les tests unitaires, de callsite et de façade publique passent. Le seul échec est :
|
||||
|
||||
```text
|
||||
global_runtime_supports_takeover_non_blocking_outputs_hot_reload_and_single_initialization
|
||||
```
|
||||
|
||||
sur :
|
||||
|
||||
```text
|
||||
assertion failed: file_text.contains("file output marker")
|
||||
```
|
||||
|
||||
Le test émet une ligne sur le sink fichier, retire immédiatement ce sink par hot reload, puis lit le fichier. Il constitue donc un test direct du contrat de drain/flush lors d'un reload.
|
||||
|
||||
## Cause de lifecycle
|
||||
|
||||
`pre.004` faisait conceptuellement :
|
||||
|
||||
```text
|
||||
reload_handle.reload(new_layers)
|
||||
retire counters
|
||||
replace outputs
|
||||
drop(old WorkerGuard)
|
||||
```
|
||||
|
||||
Le layer `fmt` retiré possède les clones `NonBlocking` utilisés pour alimenter le worker. KSP ne récupérait cependant pas explicitement l'ancien `Vec` de layers ; l'ordre entre la destruction effective de ces anciens layers et la destruction des `WorkerGuard` n'était donc pas exprimé dans notre lifecycle.
|
||||
|
||||
Pour un sink non bloquant, l'ordre voulu est explicite :
|
||||
|
||||
```text
|
||||
1. préparer complètement le nouveau runtime
|
||||
2. remplacer le Vec actif et récupérer l'ancien Vec
|
||||
3. mémoriser les dropped-line counters
|
||||
4. remplacer les outputs actifs
|
||||
5. détruire les anciens layers / NonBlocking senders
|
||||
6. détruire les anciens WorkerGuard
|
||||
7. retourner du reinitialize()
|
||||
```
|
||||
|
||||
`WorkerGuard` envoie le signal de shutdown au worker et attend son drain/flush de manière bornée. Les anciens senders doivent donc être libérés avant cette étape lorsqu'un sink vient d'être retiré.
|
||||
|
||||
## Correction
|
||||
|
||||
`reinitialize()` n'utilise plus :
|
||||
|
||||
```text
|
||||
Handle::reload(new_layers)
|
||||
```
|
||||
|
||||
pour les changements de runtime.
|
||||
|
||||
Il utilise :
|
||||
|
||||
```text
|
||||
Handle::modify(... mem::replace(active_layers, new_layers) ...)
|
||||
```
|
||||
|
||||
et récupère ainsi l'ancien `RuntimeLayers`.
|
||||
|
||||
Après succès du swap :
|
||||
|
||||
```text
|
||||
drop(retired_layers)
|
||||
drop(retired_outputs)
|
||||
```
|
||||
|
||||
est exécuté dans cet ordre.
|
||||
|
||||
Cette correction :
|
||||
|
||||
- ne change pas l'API publique ;
|
||||
- conserve le subscriber global unique ;
|
||||
- conserve le takeover KSP ;
|
||||
- conserve la préparation transactionnelle des nouveaux sinks avant le swap ;
|
||||
- conserve l'ancienne configuration lorsqu'une validation ou une construction de sink échoue avant le swap ;
|
||||
- rend explicite le lifecycle de retrait des `NonBlocking` writers avant leurs `WorkerGuard` ;
|
||||
- évite d'ajouter un sleep ou un polling temporel au test.
|
||||
|
||||
Le test d'intégration qui a révélé le défaut reste inchangé et sert directement de test de non-régression.
|
||||
|
||||
## Référence backend
|
||||
|
||||
`tracing-appender 0.2.5` documente `WorkerGuard` comme responsable du flush des logs bufferisés à sa destruction. Son implémentation de `Drop` envoie un `Msg::Shutdown` au worker puis attend le signal de fin de drain de manière bornée. KSP doit donc contrôler clairement l'ordre de destruction des senders/layers et du guard au moment d'un hot reload.
|
||||
|
||||
## Version technique
|
||||
|
||||
Ce correctif modifie du Rust. La version workspace devient :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.2-pre.4.fix.1"
|
||||
```
|
||||
|
||||
et l'en-tête du `Cargo.toml` racine devient :
|
||||
|
||||
```text
|
||||
# version: 32
|
||||
```
|
||||
|
||||
## Fichiers du delta
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-logging-lib/src/runtime.rs
|
||||
docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md
|
||||
deltas/0.1.2/pre.004-fix.001.md
|
||||
```
|
||||
|
||||
## Validations à exécuter
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Le graphe Cargo/features de `pre.004` a déjà été remonté sans doublon. Il pourra être réaudité dans `pre.005` avec les validations d'intégration finales.
|
||||
|
||||
Si ces validations sont propres, la tranche suivante reste :
|
||||
|
||||
```text
|
||||
0.1.2-pre.005 — intégration + concurrence + saturation + audits
|
||||
```
|
||||
Reference in New Issue
Block a user