Expand description
Executor delegation layer for Tower services.
This crate provides a Tower layer that delegates request processing to an
arbitrary executor for parallel processing. Unlike Tower’s Buffer layer
which processes requests serially, this layer spawns each request as a
separate task, enabling true parallelism.
§Use Cases
- CPU-bound processing: Parallelize CPU-intensive request handling
- Runtime isolation: Process requests on a dedicated runtime
- Thread pool delegation: Use specific thread pools for certain workloads
- Blocking operations: Offload blocking I/O to dedicated threads
§Example
use tower_resilience_executor::{ExecutorLayer, Executor};
use tower::{Service, ServiceBuilder, ServiceExt};
use tokio::runtime::Handle;
// Create a simple service
let service = tower::service_fn(|req: String| async move {
Ok::<_, std::convert::Infallible>(format!("Hello, {}!", req))
});
// Wrap with executor layer using current runtime
let mut service = ServiceBuilder::new()
.layer(ExecutorLayer::current())
.service(service);
// Make a request - it will be processed on a spawned task
let response = service.ready().await?.call("World".to_string()).await?;
assert_eq!(response, "Hello, World!");§Using a Dedicated Runtime
use tower_resilience_executor::ExecutorLayer;
use tower::ServiceBuilder;
// Create a dedicated runtime for heavy computation
let compute_runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(8)
.thread_name("compute")
.build()
.unwrap();
// Use the dedicated runtime for request processing
let layer = ExecutorLayer::new(compute_runtime.handle().clone());§Combining with Bulkhead
For bounded parallel execution, combine with a bulkhead layer:
ⓘ
use tower_resilience_executor::ExecutorLayer;
use tower_resilience_bulkhead::BulkheadLayer;
use tower::ServiceBuilder;
let service = ServiceBuilder::new()
// Limit concurrent requests
.layer(BulkheadLayer::builder().max_concurrent_calls(16).build())
// Execute on dedicated runtime
.layer(ExecutorLayer::current())
.service(tower::service_fn(|_: ()| async { Ok::<_, ()>(()) }));§Service Requirements
The wrapped service must implement Clone. This is necessary because each
spawned task needs its own instance of the service. Most Tower services
already implement Clone, and for those that don’t, consider wrapping
them with Buffer first.
Structs§
- Blocking
Executor - An executor that uses
spawn_blockingfor blocking operations. - Current
Runtime - An executor wrapper that spawns on the current runtime.
- Executor
Future - Future returned by
ExecutorService. - Executor
Layer - A Tower layer that delegates request processing to an executor.
- Executor
Layer Builder - Builder for configuring an
ExecutorLayer. - Executor
Service - A service that delegates request processing to an executor.
Enums§
- Executor
Error - Error type for executor service operations.
Traits§
- Executor
- Trait for executors that can spawn futures.