request_coalescer

Crates.iorequest_coalescer
lib.rsrequest_coalescer
version0.1.0
created_at2025-05-22 06:28:08.569084+00
updated_at2025-05-22 06:28:08.569084+00
descriptionAn asynchronous request coalescing library for Rust
homepage
repositoryhttps://github.com/thou-sif/request_coalescer
max_upload_size
id1684819
size66,456
(thou-sif)

documentation

README

Request Coalescer

A Rust library for coalescing identical asynchronous operations to prevent redundant work in concurrent systems.

Overview

request_coalescer provides a CoalescingService that prevents redundant work in concurrent asynchronous systems by ensuring that the underlying expensive operation is executed only once when multiple requests for the same "key" arrive simultaneously.

This is particularly useful for:

  • Deduplicating database reads or API calls for identical resources
  • Throttling access to rate-limited external services
  • Optimizing expensive computations
  • Reducing load on downstream services

Features

  • Asynchronous: Built on Tokio for efficient async operation
  • Key-based Coalescing: Deduplicate operations based on any hashable key
  • Optional Timeouts: Set global or per-operation timeouts
  • Detailed Statistics: Track coalesced, failed, and timed-out operations
  • Error Handling: Propagate errors to all waiting clients
  • Configurable: Customize behavior with various configuration options

Installation

Add the following to your Cargo.toml:

[dependencies]
request_coalescer = "0.1.0"
tokio = { version = "1", features = ["full"] } # Or specific features
anyhow = "1"
# Optional for logging/tracing:
# tracing = "0.1"
# tracing-subscriber = "0.3" # For development/examples only

Basic Usage

Here's a simple example of how to use the CoalescingService:

use request_coalescer::CoalescingService;
use std::sync::Arc;
use anyhow::Result;

async fn fetch_data(id: &str) -> Result<String> {
    // Simulate expensive operation
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
    Ok(format!("Data for {}", id))
}

#[tokio::main]
async fn main() -> Result<()> {
    // Create a new coalescing service
    let service: CoalescingService<String, String> = CoalescingService::new();

    // Execute multiple requests with the same key
    let key = "user:123".to_string();

    // These will be coalesced into a single operation
    let handle1 = {
        let svc = service.clone();
        let k = key.clone();
        tokio::spawn(async move {
            svc.execute(k, || fetch_data("user:123")).await
        })
    };

    let handle2 = {
        let svc = service.clone();
        let k = key.clone();
        tokio::spawn(async move {
            svc.execute(k, || fetch_data("user:123")).await
        })
    };

    // Both will get the same result, but the operation runs only once
    let result1 = handle1.await??;
    let result2 = handle2.await??;

    assert_eq!(result1, result2);

    Ok(())
}

Advanced Usage

Custom Configuration

You can customize the CoalescingService with various configuration options:

use request_coalescer::{CoalescingService, service::CoalescingConfig};
use std::time::Duration;
async fn main() -> Result<()> {
    
    let config = CoalescingConfig {
        timeout: Some(Duration::from_millis(200)),
        max_concurrent_ops: Some(2),
        auto_cleanup: false,
    };

    let service: CoalescingService<String, String> = CoalescingService::with_config(config);

    Ok(())
}

Timeout Handling

The library provides built-in timeout handling:

use request_coalescer::CoalescingService;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<()> {
    // Create a service with a global timeout of 1 second
    let service: CoalescingService<String, String> =
        CoalescingService::with_timeout(Duration::from_secs(1));

    // Execute with a specific timeout
    let result = service.execute_with_timeout(
        "resource".to_string(),
        Duration::from_millis(500),
        || slow_api_call("resource")
    ).await;

    Ok(())
}

API Documentation

For detailed API documentation, please run cargo doc --open or visit docs.rs (once published).

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License or Apache License 2.0, at your option.

Acknowledgments

  • This library is built on top of the Tokio async runtime.
  • Thanks to the Rust community for providing excellent tools and libraries that made this project possible.
Commit count: 4

cargo fmt