8.1 KiB
Delta 0.2.7-pre.008 — backpressure par subscription, causes terminales et cleanup borné
Base
Base directe validée par l'opérateur :
0.2.7-pre.007-fix.001
Cargo 0.2.7-pre.7.fix.1
Le checkpoint précédent est entièrement vert sur cargo fmt --all, audit Python KSP, cargo check --workspace, cargo clippy --workspace --all-targets, cargo test -p ksp-onchain-transport-lib avec 283 tests réussis, puis cargo test --workspace avec uniquement les smokes/diagnostics déjà attendus en ignored.
Objectif
Matérialiser la policy de backpressure WebSocket définie par le plan sans avancer sur les wrappers standard publics :
- queue de notifications réellement bornée par subscription ;
- aucun drop silencieux quand un consumer ne draine plus assez vite ;
- overflow isolé à la seule subscription lente ;
- compteur
overflow_countréellement incrémenté et observable sur la session ; - cause terminale KSP sûre observable sur
WsSubscription<T>; - unsubscribe distant best-effort après overflow ou terminaison locale détectée ;
- libération de la capacité
max_active_subscriptionsaprès terminaison ; - cleanup d'un receiver abandonné à la notification suivante ;
- maintien de la session physique et des subscriptions saines ;
- conservation des garanties reconnect/resubscribe acquises en
pre.007; - aucune promesse lossless et aucun backfill implicite.
Signal de version
livraison 0.2.7-pre.008
workspace.package.version 0.2.7-pre.8
commit attendu v0.2.7-pre.008
Git tag aucun
Fichiers modifiés
Cargo.toml
crates/ksp-onchain-transport-lib/README.md
crates/ksp-onchain-transport-lib/USAGE.md
crates/ksp-onchain-transport-lib/src/lib.rs
crates/ksp-onchain-transport-lib/src/ws_lifecycle.rs
crates/ksp-onchain-transport-lib/src/ws_session.rs
crates/ksp-onchain-transport-lib/src/ws_subscription.rs
crates/ksp-onchain-transport-lib/tests/public_api.rs
crates/ksp-onchain-transport-lib/unit_tests/ws_lifecycle.rs
crates/ksp-onchain-transport-lib/unit_tests/ws_session.rs
docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
Fichier ajouté
deltas/0.2.7/pre.008.md
Implémentation
Overflow par subscription
Le dispatcher typed réserve d'abord une place avec try_reserve sur la queue mpsc bornée. Une queue pleine est donc détectée avant décodage et ne bloque jamais l'actor socket :
overflow_countest incrémenté de façon saturante ;- la subscription concernée reçoit la cause terminale
ERROR_CODE_WS_BACKPRESSURE_OVERFLOW; - son état devient
Failed; - son entrée registry et son mapping remote vers local sont retirés ;
- un
*Unsubscribedistant est envoyé best-effort lorsque le binding existait ; - les autres subscriptions et la session restent actives.
Une notification déjà présente dans la queue avant l'overflow reste lisible. Après drainage de cette valeur, le receiver se ferme parce que le dispatcher actor de la subscription terminale a été libéré.
Causes terminales sûres
WsSubscription<T> expose désormais :
terminal_error_code() -> Option<ErrorCode>
La projection contient uniquement un code KSP stable et sûr. Elle ne transporte ni message RPC distant, ni payload de notification, ni URL, ni credential, ni remote subscription ID.
Les transitions runtime vers Failed publient leur cause avant de terminer le handle : overflow, mismatch protocolaire, decode typed invalide, timeout, erreur RPC applicative, échec de subscribe/resubscribe, policy Never après rupture et exhaustion terminale du reconnect. Une fermeture normale ou un unsubscribe réussi conserve None.
WsSubscriptionSnapshot peut également porter cette cause sûre lorsqu'une entrée terminale reste présente dans un snapshot de session, notamment lors d'une exhaustion globale. Les subscriptions terminales retirées du registry restent observables par leur handle local.
Cleanup et capacité
max_active_subscriptions reste une limite d'admission distincte du compteur d'overflow de notifications. Un rejet de création au plafond utilise le domaine d'erreur de capacité existant mais n'incrémente pas overflow_count.
Une subscription qui est fermée, échoue ou dont le receiver est abandonné puis détecté à la notification suivante libère son entrée locale. Le binding distant est nettoyé best-effort sans attendre son ACK et sans bloquer la session. Une nouvelle subscription peut ensuite réutiliser la capacité locale disponible avec un nouvel ID local monotone.
Le cleanup distant best-effort est également réutilisé pour les mismatchs de méthode, les erreurs de décodage typed et les ACK de resubscribe tardifs déjà traités en pre.007.
Reconnect
Une subscription devenue terminale à cause d'un overflow ou d'une autre erreur locale est retirée du registry et ne peut donc pas être sélectionnée lors d'un reconnect ultérieur. Les subscriptions saines conservent le comportement ActiveSubscriptions ou Never défini en pre.007.
overflow_count est conservé à travers les snapshots et les reconnects. Il reste distinct de continuity_gap_count : le premier décrit une saturation locale d'un consumer, le second une interruption de continuité physique.
Tests déterministes ajoutés ou renforcés
Les fixtures locales couvrent notamment :
- queue capacité 1 avec deux notifications et consumer lent ;
overflow_count == 1après saturation ;- cause terminale
ws_backpressure_overflowsur le seul handle lent ; - première notification déjà queueée encore lisible puis fermeture du receiver ;
- subscription saine parallèle toujours
Activeet recevant sa notification ; - session physique toujours
Activeaprès overflow isolé ; *Unsubscribedistant best-effort exact après overflow ;- plafond
max_active_subscriptionssans incrément du compteur d'overflow ; - capacité réutilisable après unsubscribe terminal ;
- receiver abandonné détecté sur notification suivante, cleanup distant et capacité réutilisable ;
- mismatch de méthode publiant
ws_protocol_errorsur le handle ; - decode typed invalide publiant
invalid_responsesur le handle ; - policy
Neverpubliantws_connection_failedsur le handle terminal ; - erreur RPC applicative de resubscribe publiant
rpc_application_errorsur le handle concerné.
Les tests HTTP et la surface 52+14 restent inchangés fonctionnellement.
Logging et sécurité
Tous les diagnostics passent par ksp-logging-lib avec le target crate-owned existant.
Les logs d'overflow/cleanup contiennent uniquement des métadonnées sûres : session ID local, subscription ID local, kind, compteur et code KSP. Ils ne contiennent jamais l'URL, le remote subscription ID ni le payload de notification.
Validation exécutée dans le sandbox
Le sandbox ne fournit pas cargo, rustc ni rustfmt. Aucune validation Cargo de cette tranche n'est revendiquée ici.
Les contrôles statiques KSP et l'overlay exact sont exécutés avant publication de l'archive.
Validation opérateur requise
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-onchain-transport-lib
cargo test --workspace
Décisions
overflow_countcompte uniquement les saturations des queues de notifications ; un rejet d'admission parmax_active_subscriptionsne l'incrémente pas.- Une queue pleine fait échouer la subscription au lieu de bloquer l'actor ou de dropper silencieusement des notifications.
- La cause terminale publique reste un
ErrorCodeKSP sans contenu distant arbitraire. - Le cleanup distant est best-effort et non bloquant ; la terminaison locale reste prioritaire.
- Une subscription terminale libère sa capacité locale et n'est jamais resubscribe automatiquement.
- Les wrappers WebSocket Solana standard publics restent réservés à
pre.009+.
Questions ouvertes
Aucune question bloquante pour ce checkpoint. La tranche suivante peut ouvrir le premier lot de wrappers standard stables : account, program et logs.