v0.3.11-pre.009
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/src/runtime.rs
|
||||
// version: 6
|
||||
// version: 7
|
||||
|
||||
type PersistencePort = std::sync::Arc<dyn crate::RawTransactionIngestPersistencePort + 'static>;
|
||||
type PersistenceTasks = tokio::task::JoinSet<ksp_core_lib::Result<crate::RawTransactionIngestPersistenceOutcome>>;
|
||||
type SourceTasks = tokio::task::JoinSet<ksp_core_lib::Result<()>>;
|
||||
|
||||
/// Runtime-neutral boxed future resolving after one RAW transaction ingest Worker has fully reached a terminal lifecycle state.
|
||||
pub type RawTransactionIngestTerminalFuture<'a> =
|
||||
@@ -118,12 +119,15 @@ fn current_runtime_handle() -> ksp_core_lib::Result<tokio::runtime::Handle> {
|
||||
};
|
||||
}
|
||||
|
||||
async fn drain_children(children: &mut tokio::task::JoinSet<()>) -> std::option::Option<ksp_core_lib::ErrorCode> {
|
||||
async fn drain_children(
|
||||
state: ksp_worker_api::WorkerState,
|
||||
children: &mut SourceTasks,
|
||||
snapshots: &mut crate::RawTransactionIngestSnapshotPublisher,
|
||||
) -> std::option::Option<ksp_core_lib::ErrorCode> {
|
||||
let mut fault = std::option::Option::None;
|
||||
while let std::option::Option::Some(joined) = children.join_next().await {
|
||||
if joined.is_err() && fault.is_none() {
|
||||
fault = std::option::Option::Some(crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID);
|
||||
}
|
||||
let current = source_completion(joined, state, 0, 0, snapshots);
|
||||
fault = merge_fault(fault, current);
|
||||
}
|
||||
return fault;
|
||||
}
|
||||
@@ -137,9 +141,7 @@ async fn drain_persistence(
|
||||
let mut fault = std::option::Option::None;
|
||||
while let std::option::Option::Some(joined) = persistence.join_next().await {
|
||||
let current = persistence_completion(joined, lifecycle.state(), admission.queue_depth(), persistence.len(), snapshots);
|
||||
if fault.is_none() {
|
||||
fault = current;
|
||||
}
|
||||
fault = merge_fault(fault, current);
|
||||
}
|
||||
return fault;
|
||||
}
|
||||
@@ -161,15 +163,14 @@ async fn drain_admission_and_persistence(
|
||||
std::option::Option::Some(value) => persistence_completion(value, lifecycle.state(), admission.queue_depth(), persistence.len(), snapshots),
|
||||
std::option::Option::None => std::option::Option::Some(crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID),
|
||||
};
|
||||
if fault.is_none() {
|
||||
fault = current;
|
||||
}
|
||||
fault = merge_fault(fault, current);
|
||||
}
|
||||
let received = admission.receive(settings.network()).await;
|
||||
let backpressure_wait_observed = admission.take_backpressure_wait_observed();
|
||||
match received {
|
||||
std::result::Result::Ok(std::option::Option::Some(acquisition)) => {
|
||||
let spawned = spawn_persistence(persistence, port, acquisition);
|
||||
let published = snapshots.record_admission_success(lifecycle.state(), admission.queue_depth(), persistence.len());
|
||||
let published = snapshots.record_admission_success(lifecycle.state(), admission.queue_depth(), persistence.len(), backpressure_wait_observed);
|
||||
if !spawned && fault.is_none() {
|
||||
fault = std::option::Option::Some(crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID);
|
||||
}
|
||||
@@ -181,24 +182,56 @@ async fn drain_admission_and_persistence(
|
||||
},
|
||||
std::result::Result::Ok(std::option::Option::None) => break,
|
||||
std::result::Result::Err(_) => {
|
||||
let published = snapshots.record_admission_failure(lifecycle.state(), admission.queue_depth(), persistence.len());
|
||||
if let std::result::Result::Err(error) = published {
|
||||
if fault.is_none() {
|
||||
fault = std::option::Option::Some(error.code());
|
||||
}
|
||||
} else if fault.is_none() {
|
||||
fault = std::option::Option::Some(crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID);
|
||||
let published = snapshots.record_admission_failure(lifecycle.state(), admission.queue_depth(), persistence.len(), backpressure_wait_observed);
|
||||
match published {
|
||||
std::result::Result::Ok(()) => {
|
||||
if fault.is_none() {
|
||||
fault = std::option::Option::Some(crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID);
|
||||
}
|
||||
},
|
||||
std::result::Result::Err(error) => {
|
||||
if fault.is_none() {
|
||||
fault = std::option::Option::Some(error.code());
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
let persistence_fault = drain_persistence(lifecycle, admission, persistence, snapshots).await;
|
||||
if fault.is_none() {
|
||||
fault = persistence_fault;
|
||||
}
|
||||
fault = merge_fault(fault, persistence_fault);
|
||||
return fault;
|
||||
}
|
||||
|
||||
async fn drain_owned_work(
|
||||
settings: &crate::RawTransactionIngestSettings,
|
||||
lifecycle: &ksp_worker_api::WorkerLifecycle,
|
||||
children: &mut SourceTasks,
|
||||
admission: &mut crate::RawTransactionAdmission,
|
||||
persistence: &mut PersistenceTasks,
|
||||
port: &std::option::Option<PersistencePort>,
|
||||
snapshots: &mut crate::RawTransactionIngestSnapshotPublisher,
|
||||
) -> std::option::Option<ksp_core_lib::ErrorCode> {
|
||||
let drain = async {
|
||||
let mut fault = drain_admission_and_persistence(settings, lifecycle, admission, persistence, port, snapshots).await;
|
||||
let child_fault = drain_children(lifecycle.state(), children, snapshots).await;
|
||||
fault = merge_fault(fault, child_fault);
|
||||
return fault;
|
||||
};
|
||||
let timed = tokio::time::timeout(settings.shutdown_drain_timeout(), drain).await;
|
||||
return match timed {
|
||||
std::result::Result::Ok(fault) => fault,
|
||||
std::result::Result::Err(_) => {
|
||||
admission.close();
|
||||
persistence.abort_all();
|
||||
children.abort_all();
|
||||
while persistence.join_next().await.is_some() {}
|
||||
while children.join_next().await.is_some() {}
|
||||
std::option::Option::Some(crate::ERROR_CODE_RAW_TRANSACTION_INGEST_DRAIN_TIMEOUT)
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn finish_faulted(
|
||||
lifecycle: &mut ksp_worker_api::WorkerLifecycle,
|
||||
snapshots: &mut crate::RawTransactionIngestSnapshotPublisher,
|
||||
@@ -261,6 +294,24 @@ fn persistence_completion(
|
||||
};
|
||||
}
|
||||
|
||||
fn source_completion(
|
||||
joined: std::result::Result<ksp_core_lib::Result<()>, tokio::task::JoinError>,
|
||||
state: ksp_worker_api::WorkerState,
|
||||
admission_queue_depth: usize,
|
||||
in_flight_persistence: usize,
|
||||
snapshots: &mut crate::RawTransactionIngestSnapshotPublisher,
|
||||
) -> std::option::Option<ksp_core_lib::ErrorCode> {
|
||||
match joined {
|
||||
std::result::Result::Ok(std::result::Result::Ok(())) => return std::option::Option::None,
|
||||
std::result::Result::Ok(std::result::Result::Err(_)) | std::result::Result::Err(_) => {},
|
||||
}
|
||||
let published = snapshots.record_source_failure(state, admission_queue_depth, in_flight_persistence);
|
||||
return match published {
|
||||
std::result::Result::Ok(()) => std::option::Option::Some(crate::ERROR_CODE_RAW_TRANSACTION_INGEST_SOURCE_FAILED),
|
||||
std::result::Result::Err(error) => std::option::Option::Some(error.code()),
|
||||
};
|
||||
}
|
||||
|
||||
async fn run_supervisor<Spawner>(
|
||||
settings: crate::RawTransactionIngestSettings,
|
||||
mut lifecycle: ksp_worker_api::WorkerLifecycle,
|
||||
@@ -269,9 +320,8 @@ async fn run_supervisor<Spawner>(
|
||||
mut snapshots: crate::RawTransactionIngestSnapshotPublisher,
|
||||
source_spawner: Spawner,
|
||||
) where
|
||||
Spawner: FnOnce(&mut tokio::task::JoinSet<()>, tokio::sync::watch::Receiver<bool>, tokio::sync::mpsc::Sender<crate::RawTransactionIngress>)
|
||||
+ std::marker::Send
|
||||
+ 'static,
|
||||
Spawner:
|
||||
FnOnce(&mut SourceTasks, tokio::sync::watch::Receiver<bool>, tokio::sync::mpsc::Sender<crate::RawTransactionIngress>) + std::marker::Send + 'static,
|
||||
{
|
||||
if *stop_receiver.borrow() {
|
||||
let stopping_fault = begin_stopping(&mut lifecycle, &mut snapshots, 0, 0);
|
||||
@@ -289,7 +339,7 @@ async fn run_supervisor<Spawner>(
|
||||
finish_faulted(&mut lifecycle, &mut snapshots, error.code());
|
||||
return;
|
||||
}
|
||||
let mut children = tokio::task::JoinSet::new();
|
||||
let mut children = SourceTasks::new();
|
||||
let mut persistence = PersistenceTasks::new();
|
||||
let (source_stop_sender, source_stop_receiver) = tokio::sync::watch::channel(false);
|
||||
let (mut admission, admission_sender) = crate::RawTransactionAdmission::new(settings.admission_queue_capacity());
|
||||
@@ -306,15 +356,19 @@ async fn run_supervisor<Spawner>(
|
||||
&mut snapshots,
|
||||
)
|
||||
.await;
|
||||
if fault.is_some() {
|
||||
source_stop_sender.send_replace(true);
|
||||
}
|
||||
source_stop_sender.send_replace(true);
|
||||
let stopping_fault = begin_stopping(&mut lifecycle, &mut snapshots, admission.queue_depth(), persistence.len());
|
||||
fault = merge_fault(fault, stopping_fault);
|
||||
let drain_fault = drain_admission_and_persistence(&settings, &lifecycle, &mut admission, &mut persistence, &port, &mut snapshots).await;
|
||||
fault = merge_fault(fault, drain_fault);
|
||||
let child_fault = drain_children(&mut children).await;
|
||||
fault = merge_fault(fault, child_fault);
|
||||
let drain_fault = drain_owned_work(&settings, &lifecycle, &mut children, &mut admission, &mut persistence, &port, &mut snapshots).await;
|
||||
match drain_fault {
|
||||
std::option::Option::Some(code) if code == crate::ERROR_CODE_RAW_TRANSACTION_INGEST_DRAIN_TIMEOUT => {
|
||||
fault = std::option::Option::Some(code);
|
||||
},
|
||||
std::option::Option::Some(code) => {
|
||||
fault = merge_fault(fault, std::option::Option::Some(code));
|
||||
},
|
||||
std::option::Option::None => {},
|
||||
}
|
||||
match fault {
|
||||
std::option::Option::Some(code) => finish_faulted(&mut lifecycle, &mut snapshots, code),
|
||||
std::option::Option::None => finish_stopped(&mut lifecycle, &mut snapshots),
|
||||
@@ -352,9 +406,8 @@ fn start_foundation_with_port_and_source_spawner<Spawner>(
|
||||
source_spawner: Spawner,
|
||||
) -> ksp_core_lib::Result<crate::RawTransactionIngestHandle>
|
||||
where
|
||||
Spawner: FnOnce(&mut tokio::task::JoinSet<()>, tokio::sync::watch::Receiver<bool>, tokio::sync::mpsc::Sender<crate::RawTransactionIngress>)
|
||||
+ std::marker::Send
|
||||
+ 'static,
|
||||
Spawner:
|
||||
FnOnce(&mut SourceTasks, tokio::sync::watch::Receiver<bool>, tokio::sync::mpsc::Sender<crate::RawTransactionIngress>) + std::marker::Send + 'static,
|
||||
{
|
||||
let kind = match ksp_worker_api::WorkerKindCode::new(crate::RAW_TRANSACTION_INGEST_WORKER_KIND_CODE) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
@@ -379,9 +432,8 @@ fn start_foundation_with_source_spawner<Spawner>(
|
||||
source_spawner: Spawner,
|
||||
) -> ksp_core_lib::Result<crate::RawTransactionIngestHandle>
|
||||
where
|
||||
Spawner: FnOnce(&mut tokio::task::JoinSet<()>, tokio::sync::watch::Receiver<bool>, tokio::sync::mpsc::Sender<crate::RawTransactionIngress>)
|
||||
+ std::marker::Send
|
||||
+ 'static,
|
||||
Spawner:
|
||||
FnOnce(&mut SourceTasks, tokio::sync::watch::Receiver<bool>, tokio::sync::mpsc::Sender<crate::RawTransactionIngress>) + std::marker::Send + 'static,
|
||||
{
|
||||
let port = match store_guard {
|
||||
std::option::Option::Some(store) => {
|
||||
@@ -398,7 +450,7 @@ async fn supervise_until_stop(
|
||||
lifecycle: &ksp_worker_api::WorkerLifecycle,
|
||||
source_stop_sender: &tokio::sync::watch::Sender<bool>,
|
||||
stop_receiver: &mut tokio::sync::watch::Receiver<bool>,
|
||||
children: &mut tokio::task::JoinSet<()>,
|
||||
children: &mut SourceTasks,
|
||||
admission: &mut crate::RawTransactionAdmission,
|
||||
persistence: &mut PersistenceTasks,
|
||||
port: &std::option::Option<PersistencePort>,
|
||||
@@ -427,25 +479,38 @@ async fn supervise_until_stop(
|
||||
}
|
||||
}
|
||||
joined = children.join_next(), if !children.is_empty() => {
|
||||
if let std::option::Option::Some(std::result::Result::Err(_)) = joined {
|
||||
let source_fault = match joined {
|
||||
std::option::Option::Some(value) => source_completion(value, lifecycle.state(), admission.queue_depth(), persistence.len(), snapshots),
|
||||
std::option::Option::None => std::option::Option::None,
|
||||
};
|
||||
if source_fault.is_some() {
|
||||
source_stop_sender.send_replace(true);
|
||||
return std::option::Option::Some(crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID);
|
||||
return source_fault;
|
||||
}
|
||||
}
|
||||
joined = persistence.join_next(), if !persistence.is_empty() => {
|
||||
if let std::option::Option::Some(value) = joined {
|
||||
let fault = persistence_completion(value, lifecycle.state(), admission.queue_depth(), persistence.len(), snapshots);
|
||||
if fault.is_some() {
|
||||
source_stop_sender.send_replace(true);
|
||||
return fault;
|
||||
}
|
||||
match joined {
|
||||
std::option::Option::Some(value) => {
|
||||
let fault = persistence_completion(value, lifecycle.state(), admission.queue_depth(), persistence.len(), snapshots);
|
||||
if fault.is_some() {
|
||||
source_stop_sender.send_replace(true);
|
||||
return fault;
|
||||
}
|
||||
},
|
||||
std::option::Option::None => {},
|
||||
}
|
||||
}
|
||||
received = admission.receive(settings.network()), if admission_open && persistence.len() < settings.persistence_concurrency() => {
|
||||
match received {
|
||||
std::result::Result::Ok(std::option::Option::Some(acquisition)) => {
|
||||
let backpressure_wait_observed = admission.take_backpressure_wait_observed();
|
||||
let spawned = spawn_persistence(persistence, port, acquisition);
|
||||
let published = snapshots.record_admission_success(lifecycle.state(), admission.queue_depth(), persistence.len());
|
||||
let published = snapshots.record_admission_success(
|
||||
lifecycle.state(),
|
||||
admission.queue_depth(),
|
||||
persistence.len(),
|
||||
backpressure_wait_observed,
|
||||
);
|
||||
if !spawned {
|
||||
source_stop_sender.send_replace(true);
|
||||
return std::option::Option::Some(crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID);
|
||||
@@ -455,9 +520,18 @@ async fn supervise_until_stop(
|
||||
return std::option::Option::Some(error.code());
|
||||
}
|
||||
},
|
||||
std::result::Result::Ok(std::option::Option::None) => admission_open = false,
|
||||
std::result::Result::Ok(std::option::Option::None) => {
|
||||
let _backpressure_wait_observed = admission.take_backpressure_wait_observed();
|
||||
admission_open = false;
|
||||
},
|
||||
std::result::Result::Err(_) => {
|
||||
let published = snapshots.record_admission_failure(lifecycle.state(), admission.queue_depth(), persistence.len());
|
||||
let backpressure_wait_observed = admission.take_backpressure_wait_observed();
|
||||
let published = snapshots.record_admission_failure(
|
||||
lifecycle.state(),
|
||||
admission.queue_depth(),
|
||||
persistence.len(),
|
||||
backpressure_wait_observed,
|
||||
);
|
||||
source_stop_sender.send_replace(true);
|
||||
return match published {
|
||||
std::result::Result::Ok(()) => std::option::Option::Some(crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID),
|
||||
|
||||
Reference in New Issue
Block a user