Skip to main content

Crate tower_resilience_executor

Crate tower_resilience_executor 

Source
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§

BlockingExecutor
An executor that uses spawn_blocking for blocking operations.
CurrentRuntime
An executor wrapper that spawns on the current runtime.
ExecutorFuture
Future returned by ExecutorService.
ExecutorLayer
A Tower layer that delegates request processing to an executor.
ExecutorLayerBuilder
Builder for configuring an ExecutorLayer.
ExecutorService
A service that delegates request processing to an executor.

Enums§

ExecutorError
Error type for executor service operations.

Traits§

Executor
Trait for executors that can spawn futures.