pub trait SpawnBlocking:
EthApiTypes
+ Clone
+ Send
+ Sync
+ 'static {
// Required methods
fn io_task_spawner(&self) -> impl TaskSpawner;
fn tracing_task_pool(&self) -> &BlockingTaskPool;
fn tracing_task_guard(&self) -> &BlockingTaskGuard;
fn blocking_io_task_guard(&self) -> &Arc<Semaphore>;
// Provided methods
fn acquire_owned_tracing(
&self,
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send { ... }
fn acquire_many_owned_tracing(
&self,
n: u32,
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send { ... }
fn acquire_owned_blocking_io(
&self,
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send { ... }
fn acquire_many_owned_blocking_io(
&self,
n: u32,
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send { ... }
fn acquire_weighted_blocking_io(
&self,
weight: u32,
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send { ... }
fn spawn_blocking_io<F, R>(
&self,
f: F,
) -> impl Future<Output = Result<R, Self::Error>> + Send
where F: FnOnce(Self) -> Result<R, Self::Error> + Send + 'static,
R: Send + 'static { ... }
fn spawn_blocking_io_fut<F, R, Fut>(
&self,
f: F,
) -> impl Future<Output = Result<R, Self::Error>> + Send
where Fut: Future<Output = Result<R, Self::Error>> + Send + 'static,
F: FnOnce(Self) -> Fut + Send + 'static,
R: Send + 'static { ... }
fn spawn_tracing<F, R>(
&self,
f: F,
) -> impl Future<Output = Result<R, Self::Error>> + Send
where F: FnOnce(Self) -> Result<R, Self::Error> + Send + 'static,
R: Send + 'static { ... }
}Expand description
Helpers for spawning blocking operations.
Operations can be blocking because they require lots of CPU work and/or IO.
This differentiates between workloads that are primarily CPU bound and heavier in general (such
as tracing tasks) and tasks that have a more balanced profile (io and cpu), such as eth_call
and alike.
This provides access to semaphores that permit how many of those are permitted concurrently. It’s expected that tracing related tasks are configured with a lower threshold, because not only are they CPU heavy but they can also accumulate more memory for the traces.
Required Methods§
Sourcefn io_task_spawner(&self) -> impl TaskSpawner
fn io_task_spawner(&self) -> impl TaskSpawner
Returns a handle for spawning IO heavy blocking tasks.
Runtime access in default trait method implementations.
Sourcefn tracing_task_pool(&self) -> &BlockingTaskPool
fn tracing_task_pool(&self) -> &BlockingTaskPool
Returns a handle for spawning CPU heavy blocking tasks, such as tracing requests.
Thread pool access in default trait method implementations.
Sourcefn tracing_task_guard(&self) -> &BlockingTaskGuard
fn tracing_task_guard(&self) -> &BlockingTaskGuard
Returns handle to semaphore for pool of CPU heavy blocking tasks.
Sourcefn blocking_io_task_guard(&self) -> &Arc<Semaphore>
fn blocking_io_task_guard(&self) -> &Arc<Semaphore>
Returns handle to semaphore for blocking IO tasks.
This semaphore is used to limit concurrent blocking IO operations like eth_call,
eth_estimateGas, and similar methods that require EVM execution.
Provided Methods§
Sourcefn acquire_owned_tracing(
&self,
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send
fn acquire_owned_tracing( &self, ) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send
Acquires a permit from the tracing task semaphore.
This should be used for CPU heavy operations like debug_traceTransaction,
debug_traceCall, and similar tracing methods. These tasks are typically:
- Primarily CPU bound with intensive computation
- Can accumulate significant memory for trace results
- Expected to have lower concurrency limits than general blocking IO tasks
For blocking IO tasks like eth_call or eth_estimateGas, use
acquire_owned_blocking_io instead.
See also Semaphore::acquire_owned.
Sourcefn acquire_many_owned_tracing(
&self,
n: u32,
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send
fn acquire_many_owned_tracing( &self, n: u32, ) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send
Acquires multiple permits from the tracing task semaphore.
This should be used for particularly heavy tracing operations that require more resources than a standard trace. The permit count should reflect the expected resource consumption relative to a standard tracing operation.
Like acquire_owned_tracing, this is specifically for
CPU-intensive tracing tasks, not general blocking IO operations.
See also Semaphore::acquire_many_owned.
Sourcefn acquire_owned_blocking_io(
&self,
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send
fn acquire_owned_blocking_io( &self, ) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send
Acquires a permit from the blocking IO request semaphore.
This should be used for operations like eth_call, eth_estimateGas, and similar methods
that require EVM execution and are spawned as blocking tasks.
See also Semaphore::acquire_owned.
Sourcefn acquire_many_owned_blocking_io(
&self,
n: u32,
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send
fn acquire_many_owned_blocking_io( &self, n: u32, ) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send
Acquires multiple permits from the blocking IO request semaphore.
This should be used for operations that may require more resources than a single permit allows.
See also Semaphore::acquire_many_owned.
Sourcefn acquire_weighted_blocking_io(
&self,
weight: u32,
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send
fn acquire_weighted_blocking_io( &self, weight: u32, ) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send
Acquires permits from the blocking IO request semaphore based on a calculated weight.
The weight determines the maximum number of concurrent requests of this type that can run.
For example, if the semaphore has 256 total permits and weight=10, then at most 10
concurrent requests of this type are allowed.
The permits acquired per request is calculated as total_permits / weight, with an
adjustment: if this result is even, we add 1 to ensure that weight - 1 permits are
always available for other tasks, preventing complete semaphore exhaustion.
This should be used to explicitly limit concurrent requests based on their expected resource consumption:
- Block range queries: Higher weight for larger ranges (fewer concurrent requests)
- Complex calls: Higher weight for expensive operations
- Batch operations: Higher weight for larger batches
- Historical queries: Higher weight for deeper history lookups
§Examples
// For a heavy request, use higher weight to limit concurrency
let weight = 20; // Allow at most 20 concurrent requests of this type
let _permit = self.acquire_weighted_blocking_io(weight).await?;This helps prevent resource exhaustion from concurrent expensive operations while allowing many cheap operations to run in parallel.
See also Semaphore::acquire_many_owned.
Sourcefn spawn_blocking_io<F, R>(
&self,
f: F,
) -> impl Future<Output = Result<R, Self::Error>> + Send
fn spawn_blocking_io<F, R>( &self, f: F, ) -> impl Future<Output = Result<R, Self::Error>> + Send
Executes the future on a new blocking task.
Note: This is expected for futures that are dominated by blocking IO operations, for tracing
or CPU bound operations in general use spawn_tracing.
Sourcefn spawn_blocking_io_fut<F, R, Fut>(
&self,
f: F,
) -> impl Future<Output = Result<R, Self::Error>> + Send
fn spawn_blocking_io_fut<F, R, Fut>( &self, f: F, ) -> impl Future<Output = Result<R, Self::Error>> + Send
Executes the future on a new blocking task.
Note: This is expected for futures that are dominated by blocking IO operations, for tracing
or CPU bound operations in general use spawn_tracing.
Sourcefn spawn_tracing<F, R>(
&self,
f: F,
) -> impl Future<Output = Result<R, Self::Error>> + Send
fn spawn_tracing<F, R>( &self, f: F, ) -> impl Future<Output = Result<R, Self::Error>> + Send
Executes a blocking task on the tracing pool.
Note: This is expected for futures that are predominantly CPU bound, as it uses rayon
under the hood, for blocking IO futures use spawn_blocking. See
https://ryhl.io/blog/async-what-is-blocking/.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.