v0.3.15-pre.008-fix.003
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-app-raw-transaction-ingest-desk/README.md -->
|
||||
<!-- version: 7 -->
|
||||
<!-- version: 8 -->
|
||||
|
||||
# `ksp-app-raw-transaction-ingest-desk`
|
||||
|
||||
@@ -29,7 +29,7 @@ L'inventaire de routes est calculé côté Rust à partir du composite Config va
|
||||
|
||||
Au Start, le backend revalide une sélection logique par `profile_id + route_id + inventory_generation + commitment`. Il recharge Config, reproouve le réseau Store/Transport, reconstruit le pool HTTP ou l'endpoint WS/gRPC exact requis, ouvre le Store via `ksp-store-lib`, exige un health `Ready` puis lance le Worker exact via `RawTransactionIngestWorker::start_with_runtime_resources`. Les ressources physiques et handles restent exclusivement côté Rust.
|
||||
|
||||
Le runtime est actuellement mono-route : un seul Start peut posséder le slot applicatif. Le handle Worker est installé avant l'accusé Start. Stop demande un arrêt coopératif, attend le terminal Worker, puis le monitor backend reprend l'unique `Arc<Store>` et exécute `Store::close()` avant de libérer le slot. Le partage d'un Store entre plusieurs Workers reste une responsabilité de la tranche multi-route suivante.
|
||||
Le runtime est actuellement mono-route : un seul Start peut posséder le slot applicatif. Le handle Worker est installé avant l'accusé Start. Stop demande un arrêt coopératif, attend le terminal Worker, puis le monitor backend reprend l'unique `Arc<Store>` et exécute `Store::close()` avant de libérer le slot. Si le Worker est déjà devenu terminal et que son Store a déjà été fermé, un Stop tardif retourne idempotemment le dernier état terminal sûr au lieu d'échouer comme runtime inactif. Ce cache terminal ne contient ni handle ni ressource physique et est effacé dès la réservation du Start suivant. Le partage d'un Store entre plusieurs Workers reste une responsabilité de la tranche multi-route suivante.
|
||||
|
||||
Les profils applicatifs sont réseau-centriques (`devnet`, `mainnet`, `testnet`). Un profil peut agréger plusieurs profils Transport du même réseau : le provider reste une source de capability et ne devient jamais une identité réseau ni un choix de profil applicatif.
|
||||
Une route explicitement liée à un provider n’est projetée pour un réseau que si le composite déclare une source Transport de ce provider. Ainsi, la route Helius Transaction existe sur Devnet/Mainnet mais n’est pas présentée sur Testnet tant qu’Helius ne fournit pas de source Testnet configurée.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-app-raw-transaction-ingest-desk/USAGE.md -->
|
||||
<!-- version: 6 -->
|
||||
<!-- version: 7 -->
|
||||
|
||||
# Utilisation de `ksp-app-raw-transaction-ingest-desk`
|
||||
|
||||
@@ -40,7 +40,7 @@ Les URLs, tokens, metadata secrètes, handles Transport/Store/Worker, URI Store,
|
||||
|
||||
Pour une route `Configured`, choisir `confirmed` ou `finalized` puis utiliser `Start`. Le backend revalide la génération d'inventaire et la composition Config, ouvre le Store correspondant, exige son état `Ready`, construit le Worker exact et installe son handle avant de renvoyer l'accusé runtime.
|
||||
|
||||
Un seul Worker peut être actif ou en démarrage dans cette tranche. Un second Start est refusé tant que le Worker précédent n'est pas terminal et que son Store n'a pas été explicitement fermé. `Stop` est coopératif : la commande attend le terminal Worker et la fermeture Store avant de rendre le slot à nouveau disponible.
|
||||
Un seul Worker peut être actif ou en démarrage dans cette tranche. Un second Start est refusé tant que le Worker précédent n'est pas terminal et que son Store n'a pas été explicitement fermé. `Stop` est coopératif : la commande attend le terminal Worker et la fermeture Store avant de rendre le slot à nouveau disponible. Si le Worker est déjà terminal et nettoyé avant le clic Stop, la commande retourne idempotemment le dernier état terminal sûr ; ce comportement permet de resynchroniser le contrôle `pre.008` sans introduire le monitoring continu réservé à une tranche ultérieure.
|
||||
|
||||
Le frontend n'effectue aucun polling runtime continu dans cette tranche. Une terminaison spontanée est nettoyée côté backend ; sa projection temps réel vers l'UI appartient au monitoring ultérieur.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-raw-transaction-ingest-desk/src/route_runtime.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
//! Mono-route Store and Worker lifecycle owned by Raw Transaction Ingest Desk.
|
||||
|
||||
@@ -8,6 +8,7 @@ const STORE_RECLAIM_POLL_INTERVAL: std::time::Duration = std::time::Duration::fr
|
||||
const STORE_RECLAIM_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(1);
|
||||
|
||||
struct RouteRuntimeInner {
|
||||
last_terminal: std::option::Option<crate::RawIngestRouteRuntimeDto>,
|
||||
next_sequence: u64,
|
||||
slot: RouteRuntimeSlot,
|
||||
}
|
||||
@@ -21,7 +22,9 @@ impl crate::RouteRuntimeState {
|
||||
/// Creates an idle mono-route runtime state.
|
||||
#[must_use]
|
||||
pub(crate) fn new() -> Self {
|
||||
return Self { inner: std::sync::Mutex::new(RouteRuntimeInner { next_sequence: 0, slot: RouteRuntimeSlot::Idle }) };
|
||||
return Self {
|
||||
inner: std::sync::Mutex::new(RouteRuntimeInner { last_terminal: std::option::Option::None, next_sequence: 0, slot: RouteRuntimeSlot::Idle }),
|
||||
};
|
||||
}
|
||||
|
||||
fn reserve(&self, prepared: &crate::PreparedRouteStart) -> ksp_core_lib::Result<RouteRuntimeReservation> {
|
||||
@@ -63,6 +66,7 @@ impl crate::RouteRuntimeState {
|
||||
profile_id: prepared.profile_id.clone(),
|
||||
route_id: prepared.route_id,
|
||||
};
|
||||
inner.last_terminal = std::option::Option::None;
|
||||
inner.next_sequence = sequence;
|
||||
inner.slot = RouteRuntimeSlot::Starting { token: sequence };
|
||||
return std::result::Result::Ok(RouteRuntimeReservation { identity, token: sequence, worker_id });
|
||||
@@ -103,13 +107,14 @@ impl crate::RouteRuntimeState {
|
||||
}
|
||||
}
|
||||
|
||||
fn finish(&self, token: u64) {
|
||||
fn finish(&self, token: u64, terminal: crate::RawIngestRouteRuntimeDto) {
|
||||
let inner = self.inner.lock();
|
||||
let mut inner = match inner {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
if matches!(&inner.slot, RouteRuntimeSlot::Active { token: current, .. } if *current == token) {
|
||||
inner.last_terminal = std::option::Option::Some(terminal);
|
||||
inner.slot = RouteRuntimeSlot::Idle;
|
||||
}
|
||||
}
|
||||
@@ -124,9 +129,16 @@ impl crate::RouteRuntimeState {
|
||||
};
|
||||
match &inner.slot {
|
||||
RouteRuntimeSlot::Active { handle, identity, .. } => std::result::Result::Ok((handle.clone(), identity.clone())),
|
||||
RouteRuntimeSlot::Idle | RouteRuntimeSlot::Starting { .. } => std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
RouteRuntimeSlot::Idle => match &inner.last_terminal {
|
||||
std::option::Option::Some(terminal) => return std::result::Result::Ok(terminal.clone()),
|
||||
std::option::Option::None => std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_ROUTE_RUNTIME_NOT_ACTIVE,
|
||||
"Raw Transaction Ingest Desk has no active mono-route Worker to stop",
|
||||
)),
|
||||
},
|
||||
RouteRuntimeSlot::Starting { .. } => std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_ROUTE_RUNTIME_NOT_ACTIVE,
|
||||
"Raw Transaction Ingest Desk has no active mono-route Worker to stop",
|
||||
"Raw Transaction Ingest Desk mono-route Worker is still starting and cannot be stopped yet",
|
||||
)),
|
||||
}
|
||||
};
|
||||
@@ -147,7 +159,12 @@ impl crate::RouteRuntimeState {
|
||||
};
|
||||
let started = std::time::Instant::now();
|
||||
loop {
|
||||
if self.is_idle()? {
|
||||
let idle = self.is_idle();
|
||||
let idle = match idle {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
if idle {
|
||||
return std::result::Result::Ok(identity.dto(project_worker_state(terminal)));
|
||||
}
|
||||
if started.elapsed() >= ROUTE_STOP_CLEANUP_TIMEOUT {
|
||||
@@ -189,7 +206,7 @@ impl crate::RouteRuntimeLaunch {
|
||||
/// Waits for terminal Worker state, explicitly closes Store after the Worker releases its `Arc`, then frees the mono-route slot.
|
||||
pub(crate) async fn monitor(self) {
|
||||
let terminal = self.handle.wait_terminal().await;
|
||||
match terminal {
|
||||
let terminal_state = match terminal {
|
||||
std::result::Result::Ok(state) => {
|
||||
ksp_logging_lib::info!(
|
||||
target: crate::TRACING_TARGET,
|
||||
@@ -197,6 +214,7 @@ impl crate::RouteRuntimeLaunch {
|
||||
worker_state = state.code(),
|
||||
"Raw Transaction Ingest Desk mono-route Worker reached terminal state"
|
||||
);
|
||||
project_worker_state(state)
|
||||
},
|
||||
std::result::Result::Err(error) => {
|
||||
ksp_logging_lib::warn!(
|
||||
@@ -206,8 +224,9 @@ impl crate::RouteRuntimeLaunch {
|
||||
error_code = error.code().code(),
|
||||
"Raw Transaction Ingest Desk terminal Worker wait failed"
|
||||
);
|
||||
crate::RawIngestRouteState::Faulted
|
||||
},
|
||||
}
|
||||
};
|
||||
let close = close_store_arc(self.store).await;
|
||||
if let std::result::Result::Err(error) = close {
|
||||
ksp_logging_lib::warn!(
|
||||
@@ -218,7 +237,9 @@ impl crate::RouteRuntimeLaunch {
|
||||
"Raw Transaction Ingest Desk Store shutdown failed after terminal Worker"
|
||||
);
|
||||
}
|
||||
self.runtime_state.finish(self.token);
|
||||
let mut terminal = self.acknowledgement;
|
||||
terminal.state = terminal_state;
|
||||
self.runtime_state.finish(self.token, terminal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-raw-transaction-ingest-desk/tests/release_completeness.rs
|
||||
// version: 5
|
||||
// version: 6
|
||||
|
||||
//! Release-completeness canaries for Raw Transaction Ingest Desk Start-resource reconstruction.
|
||||
|
||||
@@ -98,7 +98,9 @@ fn pre_008_mono_route_slot_blocks_second_start_until_terminal_store_cleanup() {
|
||||
"RouteRuntimeSlot::Starting",
|
||||
"RouteRuntimeSlot::Active",
|
||||
"ERROR_CODE_ROUTE_RUNTIME_ACTIVE",
|
||||
"runtime_state.finish(self.token)",
|
||||
"inner.last_terminal = std::option::Option::None",
|
||||
"std::option::Option::Some(terminal) => return std::result::Result::Ok(terminal.clone())",
|
||||
"self.runtime_state.finish(self.token, terminal)",
|
||||
"Arc::try_unwrap",
|
||||
] {
|
||||
assert!(runtime.contains(required), "missing mono-route ownership marker {required}");
|
||||
|
||||
Reference in New Issue
Block a user