SpawnBlocking

Trait SpawnBlocking 

Source
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 { ... }
}
Available on crate feature rpc only.
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§

Source

fn io_task_spawner(&self) -> impl TaskSpawner

Returns a handle for spawning IO heavy blocking tasks.

Runtime access in default trait method implementations.

Source

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.

Source

fn tracing_task_guard(&self) -> &BlockingTaskGuard

Returns handle to semaphore for pool of CPU heavy blocking tasks.

Source

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§

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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,

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.

Source

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,

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.

Source

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,

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.

Implementors§

Source§

impl<N, Rpc> SpawnBlocking for EthApi<N, Rpc>
where N: RpcNodeCore, Rpc: RpcConvert<Error = EthApiError>,