thread_spawn_critical.rs
Overview
This file defines and implements the SpawnCritical trait, which extends the functionality of std::thread::Builder to spawn threads that run critical tasks. The key feature of these critical threads is that if the thread's closure returns an error, the program logs the error and immediately terminates the entire process with a specific exit code. This approach ensures that critical failures in spawned threads do not go unnoticed or unhandled silently.
The trait provides two methods:
spawn_critical: Spawns a detached thread running a closure that returns aResult. If the closure returns an error, the process exits.spawn_scoped_critical: Spawns a scoped thread with similar error-handling semantics, ensuring safe borrowing within the thread's scope.
The implementation uses anyhow::Result for error handling and tracing for logging, integrating with existing error and logging infrastructure.
Trait: SpawnCritical
The SpawnCritical trait defines two methods to spawn threads that run critical tasks:
pub trait SpawnCritical {
fn spawn_critical<F, T>(self, f: F) -> std::io::Result<std::thread::JoinHandle<T>>
where
F: FnOnce() -> anyhow::Result<T> + Send + 'static,
T: Send + 'static;
fn spawn_scoped_critical<'scope, 'env, F, T>(
self,
scope: &'scope std::thread::Scope<'scope, 'env>,
f: F,
) -> std::io::Result<std::thread::ScopedJoinHandle<'scope, T>>
where
F: FnOnce() -> anyhow::Result<T> + Send + 'scope,
T: Send + 'scope;
}
spawn_critical
Parameters:
self: The thread builder (std::thread::Builder) consuming self to configure the thread.f: A closure with signatureFnOnce() -> anyhow::Result<T> + Send + 'static. The closure performs the thread's logic and returns aResult.
Returns: A
Resultwrapping aJoinHandle<T>. On spawning failure, returns anstd::io::Error.Behavior: Executes the closure inside the new thread. If the closure returns
Ok(value), the thread returns that value. If it returnsErr(error), logs the error message usingtracing::error!with the thread name, then immediately terminates the process with exit code 101.Usage Example:
use std::thread;
let builder = thread::Builder::new().name("critical_thread".into());
let handle = builder.spawn_critical(|| {
// Critical code here
if something_went_wrong {
Err(anyhow::anyhow!("Something failed"))
} else {
Ok(42)
}
})?;
let result = handle.join().unwrap();
spawn_scoped_critical
Parameters:
self: The thread builder (std::thread::Builder).scope: A reference to the lifetime-scoped thread scope (&std::thread::Scope).f: A closure with signatureFnOnce() -> anyhow::Result<T> + Send + 'scope.
Returns: A
Resultwrapping aScopedJoinHandle<'scope, T>. On failure, returns anstd::io::Error.Behavior: Similar to
spawn_critical, but the closure runs within a scoped thread, allowing safe borrowing of data from the enclosing scope. If the closure returns an error, logs and terminates the process as above.Usage Example:
std::thread::scope(|scope| {
let builder = std::thread::Builder::new().name("scoped_critical".into());
let handle = builder.spawn_scoped_critical(scope, || {
// Critical scoped code
Ok("done")
})?;
let result = handle.join().unwrap();
Ok::<(), std::io::Error>(())
});
Implementation Details
The trait SpawnCritical is implemented for std::thread::Builder, effectively extending the builder API with critical thread spawning capabilities.
Error Handling and Process Termination
Both methods wrap the provided closure
finside amatchstatement.If the closure returns
Ok, the value is returned normally.If it returns
Err:The current thread's name is obtained with
std::thread::current().name(). If no name is set, defaults to"unknown".Logs the error message along with the thread name using
tracing::error!.Calls
std::process::exit(101)to terminate the entire process immediately with exit code 101.
The choice of exit code 101 is a fixed indicator representing a critical thread failure.
Thread Naming and Logging
The thread's name is included in the error log to identify which critical thread caused the failure.
Logging uses the
tracingcrate, which integrates with structured logging and telemetry systems, facilitating observability.
Lifetimes and Thread Safety
The
spawn_scoped_criticalmethod uses lifetimes'scopeand'envto ensure safe borrowing within scoped threads, following the pattern ofstd::thread::scope.Both methods require
FandTto beSendto guarantee safe transfer across thread boundaries.The closure
Fmust be'staticfor detached threads and'scopefor scoped threads.
Interaction with the System
This file extends the thread creation mechanism, enabling critical error handling semantics that enforce process termination on thread failure.
Relies on the standard library's thread API (
std::thread::Builder,std::thread::JoinHandle,std::thread::Scope,std::thread::ScopedJoinHandle).Depends on the
anyhowcrate for error handling with rich context.Uses the
tracingcrate for logging error messages.Ensures that any spawned thread using this trait participates in the application's error and logging infrastructure.
Can be used wherever threads are spawned to guarantee that critical failures do not fail silently or cause inconsistent state.
Mermaid Diagram
classDiagram
class SpawnCritical {
+spawn_critical()
+spawn_scoped_critical()
}
class std::thread::Builder {
+spawn()
+spawn_scoped()
}
SpawnCritical <|.. std::thread::Builder
%% Method behavior
class SpawnCriticalMethods {
<<interface>>
+call closure f() -> Result<T>
+on Ok: return value
+on Err: log error, exit(101)
}
SpawnCriticalMethods <|-- SpawnCritical
This diagram shows the relationship between the SpawnCritical trait and std::thread::Builder, highlighting the two main methods and their critical error handling behavior.