4.3 KiB
Delta 0.1.2-pre.004-fix.001
Base requise
Livraison précédente :
0.1.2-pre.004
La base porte :
workspace.package.version = "0.1.2-pre.4"
Cargo.toml header version = 31
Validations remontées
Les validations utilisateur de pre.004 sont :
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 :
global_runtime_supports_takeover_non_blocking_outputs_hot_reload_and_single_initialization
sur :
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 :
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 :
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 :
Handle::reload(new_layers)
pour les changements de runtime.
Il utilise :
Handle::modify(... mem::replace(active_layers, new_layers) ...)
et récupère ainsi l'ancien RuntimeLayers.
Après succès du swap :
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
NonBlockingwriters avant leursWorkerGuard; - é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 :
workspace.package.version = "0.1.2-pre.4.fix.1"
et l'en-tête du Cargo.toml racine devient :
# version: 32
Fichiers du delta
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
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 :
0.1.2-pre.005 — intégration + concurrence + saturation + audits