| Crates.io | rs2-stream |
| lib.rs | rs2-stream |
| version | 0.3.3 |
| created_at | 2025-06-17 16:25:16.048636+00 |
| updated_at | 2025-06-24 21:22:01.074412+00 |
| description | A high-performance, production-ready async streaming library for Rust. |
| homepage | https://github.com/VishnuRaman/rs2 |
| repository | https://github.com/VishnuRaman/rs2 |
| max_upload_size | |
| id | 1715985 |
| size | 1,320,820 |
RS2 is a high-performance, async streaming library for Rust that combines the ergonomics of reactive streams with reliability features. Built for applications that demand both developer productivity and operational excellence.
RS2 is also a stateful streaming library with built-in state management capabilities, enabling complex stateful operations like session tracking, deduplication, windowing, and real-time analytics without external dependencies.
Scaling Performance: While RS2 has modest sequential overhead (1.6x vs futures-rs, comparable to tokio-stream), it delivers parallel performance with near-linear scaling up to 16+ cores and 7.8-8.5x speedup for I/O-bound workloads.
Reliability: Unlike basic streaming libraries, RS2 includes built-in automatic backpressure, retry policies with exponential backoff, circuit breakers, timeout handling, and resource management - eliminating the need to manually implement these critical patterns.
Stateful Stream Processing: RS2 provides built-in state management with support for stateful operations like deduplication, windowing, session tracking, and real-time analytics. No external state stores required - everything is handled internally with configurable storage backends.
Effortless Parallelization: Transform any sequential stream into parallel processing with a single method call. RS2's par_eval_map_rs2() automatically handles concurrency, ordering, and error propagation.
External streaming frameworks Integration: First-class connector system for Kafka, and custom systems with health checks, metrics, and automatic retry logic built-in.
See RS2 in action with these examples:
Understanding RS2's parallel processing capabilities:
cargo run --example parallel_processing_comprehensive
Stateful streaming analytics system:
cargo run --example real_time_analytics_pipeline
These examples demonstrate RS2's capabilities - from basic parallel processing to complex stateful analytics pipelines. Understanding how to build streaming applications!
Based on Criterion.rs benchmarks on test hardware
| Operation | 1K Items | 10K Items | 100K Items | 1M Items | Throughput (1K) |
|---|---|---|---|---|---|
| Map/Filter | 4.05-4.15 µs | 38.73-38.75 µs | 393.94-394.84 µs | 4.04-4.07 ms | ~247K items/sec |
| Fold | 2.69-2.70 µs | 26.81-26.90 µs | 269.63-270.28 µs | 2.68-2.69 ms | ~357K items/sec |
| Chunk Process | 4.21-4.97 µs | 34.44-34.55 µs | 345.44-345.64 µs | 3.60-3.96 ms | ~260K items/sec |
| Operation | 1K Items | 10K Items | 50K Items | Throughput (1K) |
|---|---|---|---|---|
| Eval Map | 20.08-20.13 µs | 201.35-201.94 µs | 1.01-1.02 ms | ~50K items/sec |
| Concurrency | Sequential | Parallel Ordered | Parallel Unordered | Speedup Factor |
|---|---|---|---|---|
| 8 cores | 4.07s | 530ms | 530ms | 7.7x |
| 16 cores | 4.07s | 281ms | 282ms | 14.5x |
| 32 cores | 4.07s | 160ms | 160ms | 25.4x |
| 64 cores | 4.07s | 99ms | 99ms | 41.1x |
| Concurrency | Sequential | Parallel Ordered | Parallel Unordered | Speedup Factor |
|---|---|---|---|---|
| 2 cores | 7.06µs | 3.18ms | 3.15ms | 0.004x |
| 4 cores | 7.06µs | 1.79ms | 1.78ms | 0.004x |
| Concurrency | Sequential | Parallel Ordered | Parallel Unordered | Speedup Factor |
|---|---|---|---|---|
| 2 cores | 563µs | 743µs | 732µs | 0.76x |
| 4 cores | 563µs | 750µs | 733µs | 0.75x |
| 8 cores | 563µs | 778µs | 797µs | 0.72x |
| Concurrency | Sequential | Parallel Ordered | Parallel Unordered | Speedup Factor |
|---|---|---|---|---|
| 2 cores | 9.98ms | 10.77ms | 10.91ms | 0.93x |
| 4 cores | 9.98ms | 10.83ms | 10.83ms | 0.92x |
| 8 cores | 9.98ms | 10.82ms | 10.72ms | 0.93x |
| 16 cores | 9.98ms | 10.56ms | 10.42ms | 0.96x |
| Concurrency | Sequential | Parallel Ordered | Parallel Unordered | Speedup Factor |
|---|---|---|---|---|
| 4 cores | 676µs | 1.07ms | 1.02ms | 0.63x |
| 8 cores | 676µs | 1.01ms | 1.01ms | 0.67x |
| 16 cores | 676µs | 995µs | 991µs | 0.68x |
| Cores | Time | vs Sequential |
|---|---|---|
| 1 | 9.80ms | 1.00x |
| 2 | 10.64ms | 0.92x |
| 4 | 10.76ms | 0.91x |
| 8 | 10.53ms | 0.93x |
| 16 | 10.27ms | 0.95x |
| 32 | 10.01ms | 0.98x |
| Cores | Time | vs Sequential |
|---|---|---|
| 1 | 2.04s | 1.00x |
| 2 | 1.03s | 1.98x |
| 4 | 545ms | 3.74x |
| 8 | 286ms | 7.12x |
| 16 | 160ms | 12.7x |
| 32 | 99ms | 20.6x |
| Cores | Time | vs Sequential |
|---|---|---|
| 1 | 168µs | 1.00x |
| 2 | 348µs | 0.48x |
| 4 | 256µs | 0.66x |
| 8 | 241µs | 0.70x |
| 16 | 207µs | 0.81x |
| 32 | 195µs | 0.86x |
| Concurrency | Time | vs Sequential |
|---|---|---|
| 1 | 3.05s | 1.00x |
| 2 | 1.53s | 1.99x |
| 4 | 781ms | 3.91x |
| 8 | 406ms | 7.51x |
| 16 | 219ms | 13.9x |
| 32 | 129ms | 23.6x |
| 64 | 83ms | 36.7x |
| Concurrency | Time | vs Sequential |
|---|---|---|
| 1 | 14.89ms | 1.00x |
| 2 | 16.57ms | 0.90x |
| 4 | 16.74ms | 0.89x |
| 8 | 16.50ms | 0.90x |
| 16 | 16.10ms | 0.93x |
| Method | Time | vs Sequential |
|---|---|---|
| Sequential | 5.98µs | 1.00x |
| Map Parallel | 460µs | 0.013x |
| Map Parallel (2 cores) | 3.14ms | 0.002x |
| Map Parallel (4 cores) | 1.77ms | 0.003x |
| Method | Time | vs Sequential |
|---|---|---|
| Sequential | 573µs | 1.00x |
| Map Parallel | 742µs | 0.77x |
| Map Parallel (2 cores) | 792µs | 0.72x |
| Map Parallel (4 cores) | 742µs | 0.77x |
| Map Parallel (8 cores) | 749µs | 0.76x |
| Method | Time | vs Sequential |
|---|---|---|
| Sequential | 9.78ms | 1.00x |
| Map Parallel | 10.41ms | 0.94x |
| Map Parallel (2 cores) | 10.81ms | 0.90x |
| Map Parallel (4 cores) | 10.72ms | 0.91x |
| Map Parallel (8 cores) | 10.64ms | 0.92x |
| Map Parallel (16 cores) | 10.36ms | 0.94x |
| Method | Time | vs Sequential |
|---|---|---|
| Sequential | 19.99ms | 1.00x |
| Map Parallel | 21.60ms | 0.93x |
| Map Parallel (concurrency) | 21.48ms | 0.93x |
| Par Eval Map | 21.59ms | 0.93x |
| Par Eval Map (unordered) | 21.46ms | 0.93x |
These benchmarks represent actual performance on the test hardware. Results may vary based on system configuration and workload characteristics.
Based on Criterion.rs benchmarks on test hardware
| Operation | 1K Items | 10K Items | Throughput (1K) | Notes |
|---|---|---|---|---|
| Stateful Map | 653.54-655.34 µs | 6.4788-6.4863 ms | ~1.53M items/sec | Standard stateful operation |
| Stateful Filter | 638.71-640.32 µs | 6.4290-6.4758 ms | ~1.56M items/sec | Similar to stateful map |
| Stateful Fold | 629.79-630.10 µs | 6.2187-6.2300 ms | ~1.59M items/sec | Most efficient stateful operation |
| Stateful Window | 131.47-131.94 µs | 1.2135-1.2191 ms | ~7.6M items/sec | Highly optimized |
| Stateful Join | 759.11-761.31 µs (500 items) | 2.2078-2.2149 ms (1K items) | ~658K items/sec | Complex operation |
| Stateful Group By | 159.22-160.18 µs (500 items) | 255.12-255.42 µs (1K items) | ~3.1M items/sec | Efficient grouping |
| Operation | 1K Items | 10K Items | Throughput (1K) | Use Case |
|---|---|---|---|---|
| Stateful Deduplicate | 212.65-213.14 µs | 1.8903-1.8989 ms | ~4.7M items/sec | Remove duplicates |
| Stateful Throttle | 466.61-468.10 µs | 4.4923-4.4998 ms | ~2.14M items/sec | Rate limiting |
| Stateful Session | 463.59-466.12 µs | 4.6182-4.6219 ms | ~2.15M items/sec | Session tracking |
| Storage Type | 1K Items | 10K Items | Performance |
|---|---|---|---|
| In-Memory | 670.86-673.17 µs | 6.4952-6.5164 ms | Baseline |
| Custom Storage | 513.22-515.54 µs | 5.1436-5.1601 ms | ~22% faster |
| Cardinality | 1K Items | 10K Items | Performance Impact |
|---|---|---|---|
| Low Cardinality | 669.18-671.55 µs | 6.4367-6.4516 ms | Baseline performance |
| High Cardinality | 664.73-669.03 µs | 142.89-143.85 ms | Significant degradation at scale |
Note: High cardinality shows predictable performance degradation rather than system failure, with 22x slowdown at 10K items being controlled and stable.
Performance measurements based on Criterion.rs benchmarks. Results may vary based on hardware and workload characteristics.
Performance can vary by ±0.5-2.5% between runs, as shown in the benchmark change percentages. All measurements represent statistically significant results with outlier detection.
Benchmark results last updated: 2025-01-21 (after resource management optimizations)
RS2 is optimized for the 95% of use cases where developer productivity, operational reliability, and parallel performance matter more than raw sequential speed. Suitable for microservices, data pipelines, API gateways, and any application requiring stream processing.
The benchmark results demonstrate that RS2 handles high cardinality gracefully:
| Cardinality Type | 1K Items | 10K Items | Actual Impact |
|---|---|---|---|
| Low Cardinality | 658.31 µs | 6.49 ms | Baseline performance |
| High Cardinality | 612.29 µs | 143.36 ms | Controlled degradation |
✅ High Cardinality Protection Works:
✅ Built-in Safeguards:
RS2's state management already includes the protection mechanisms needed:
So the benchmark actually validates that RS2's high cardinality protection works as designed - it gracefully handles the load while maintaining system stability.
RS2 provides stateful stream processing capabilities:
RS2 provides flexible state configuration with predefined presets and custom options:
use rs2::state::{StateConfigs, StateConfigBuilder};
// Predefined configurations
let session_config = StateConfigs::session(); // 30min TTL, 5min cleanup
let high_perf_config = StateConfigs::high_performance(); // 1hr TTL, 1min cleanup
let short_lived_config = StateConfigs::short_lived(); // 5min TTL, 30s cleanup
let long_lived_config = StateConfigs::long_lived(); // 7day TTL, 1hr cleanup
// Custom configuration
let custom_config = StateConfigBuilder::new()
.ttl(Duration::from_secs(3600))
.cleanup_interval(Duration::from_secs(300))
.max_size(50000)
.custom_storage(my_custom_storage)
.build()
.unwrap();
For comprehensive state management documentation, see docs/state_management.md.
RS2 provides advanced analytics capabilities for real-time data processing:
window_by_time_rs2(config, timestamp_fn) - Create time-based windows from timestamped eventsjoin_with_time_window_rs2(other, config, timestamp_fn1, timestamp_fn2, join_fn, key_selector) - Join streams with time windowsFor examples of advanced analytics, see examples/advanced_analytics_example.rs. This example demonstrates:
// This example demonstrates:
// - Time-based windowed aggregations with custom time semantics
// - Stream joins with time windows for event enrichment
// - Real-world user behavior analysis scenarios
// - System monitoring with time-based metrics
// See the full code at examples/advanced_analytics_example.rs
RS2 provides resource management for all streaming operations. This includes:
get_global_resource_manager() for custom tracking or metrics.use rs2_stream::resource_manager::get_global_resource_manager;
let resource_manager = get_global_resource_manager();
// Track allocation of a custom resource (e.g., 4096 bytes)
resource_manager.track_memory_allocation(4096).await?;
// ... use the resource ...
// Track deallocation when done
resource_manager.track_memory_deallocation(4096).await;
You can customize resource management thresholds and behavior via ResourceConfig:
use rs2_stream::resource_manager::ResourceConfig;
let config = ResourceConfig {
max_memory_bytes: 512 * 1024 * 1024, // 512MB
max_keys: 50_000,
memory_threshold_percent: 75,
buffer_overflow_threshold: 5_000,
cleanup_interval: std::time::Duration::from_secs(60),
emergency_cleanup_threshold: 90,
};
For most users, the default configuration is sufficient.
For examples of resource management, see examples/resource_management_example.rs. This example demonstrates:
// This example demonstrates:
// - Memory tracking and circuit breaking
// - Custom resource configurations
// - Monitoring and cleanup strategies
// - Global resource manager patterns
// See the full code at examples/resource_management_example.rs
Add RS2 to your Cargo.toml:
[dependencies]
rs2-stream = "0.3.3"
For basic usage examples, see examples/basic_usage.rs.
// This example demonstrates basic stream creation and transformation
// See the full code at examples/basic_usage.rs
For a more complex example that processes a stream of users, demonstrating several RS2 features, see examples/processing_stream_of_users.rs.
// This example demonstrates:
// - Creating streams from async functions
// - Applying backpressure
// - Filtering and transforming streams
// - Grouping elements by key
// - Parallel processing with bounded concurrency
// - Timeout handling
// See the full code at examples/processing_stream_of_users.rs
This example demonstrates:
emit(item) - Create a stream that emits a single elementempty() - Create an empty streamfrom_iter(iter) - Create a stream from an iteratoreval(future) - Evaluate a Future and emit its outputrepeat(item) - Create a stream that repeats a valueemit_after(item, duration) - Create a stream that emits a value after a delayunfold(init, f) - Create a stream by repeatedly applying a functionemit, empty, and from_iterFor examples of basic stream creation, see examples/stream_creation_basic.rs.
// This example demonstrates:
// - Creating a stream with a single element using emit()
// - Creating an empty stream using empty()
// - Creating a stream from an iterator using from_iter()
// See the full code at examples/stream_creation_basic.rs
eval and emit_afterFor examples of async stream creation, see examples/stream_creation_async.rs.
// This example demonstrates:
// - Creating a stream by evaluating a future using eval()
// - Creating a stream that emits a value after a delay using emit_after()
// See the full code at examples/stream_creation_async.rs
repeat and unfoldFor examples of creating infinite streams, see examples/stream_creation_infinite.rs.
// This example demonstrates:
// - Creating an infinite stream that repeats a value using repeat()
// - Creating an infinite stream by repeatedly applying a function using unfold()
// See the full code at examples/stream_creation_infinite.rs
map_rs2(f) - Apply a function to each elementfilter_rs2(predicate) - Keep only elements that satisfy the predicateflat_map_rs2(f) - Apply a function that returns a stream to each element and flatten the resultseval_map_rs2(f) - Map elements with an async functionchunk_rs2(size) - Collect elements into chunks of the specified sizetake_rs2(n) - Take the first n elementsskip_rs2(n) - Skip the first n elementsdistinct_rs2() - Remove duplicate elementsdistinct_until_changed_rs2() - Remove consecutive duplicate elementsdistinct_by_rs2(f) - Remove duplicate elements based on a key functiondistinct_until_changed_by_rs2(f) - Remove consecutive duplicate elements based on a key functionFor examples of basic transformations, see examples/transformations_basic.rs.
// This example demonstrates:
// - Mapping elements using map_rs2()
// - Filtering elements using filter_rs2()
// - Flattening nested streams using flat_map_rs2()
// See the full code at examples/transformations_basic.rs
For examples of async transformations, see examples/transformations_async.rs.
// This example demonstrates:
// - Mapping elements with async functions using eval_map_rs2()
// - Filtering elements with async predicates using eval_filter_rs2()
// See the full code at examples/transformations_async.rs
For examples of combining streams, see examples/transformations_combining.rs.
// This example demonstrates:
// - Concatenating streams using concat_rs2()
// - Merging streams using merge_rs2()
// - Zipping streams using zip_rs2()
// See the full code at examples/transformations_combining.rs
For examples of interleaving streams, see examples/interleave_example.rs.
// This example demonstrates:
// - Interleaving multiple streams in round-robin fashion using interleave_rs2()
// - Interleaving streams with different lengths
// - Interleaving streams that emit items at different rates
// - Using interleaving for multiplexing data sources
// See the full code at examples/interleave_example.rs
For examples of grouping elements, see examples/transformations_grouping.rs and examples/chunk_rs2_example.rs.
// This example demonstrates:
// - Grouping elements by key using group_by_rs2()
// - Grouping elements into chunks using chunks_rs2()
// - Collecting elements into chunks of specified size using chunk_rs2()
// See the full code at examples/transformations_grouping.rs and examples/chunk_rs2_example.rs
For examples of slicing operations, see examples/transformations_slicing.rs.
// This example demonstrates:
// - Taking elements using take_rs2()
// - Skipping elements using skip_rs2()
// See the full code at examples/transformations_slicing.rs
For examples of sliding windows, see examples/sliding_window_example.rs.
// This example demonstrates:
// - Creating sliding windows of elements using sliding_window_rs2()
// - Using sliding windows for time series analysis
// - Creating phrases from sliding windows of words
// See the full code at examples/sliding_window_example.rs
For examples of batch processing, see examples/batch_process_example.rs.
// This example demonstrates:
// - Processing elements in batches using batch_process_rs2()
// - Transforming batches of elements
// - Using batch processing for database operations
// - Combining batch processing with async operations
// See the full code at examples/batch_process_example.rs
fold_rs2(init, f) - Accumulate a value over a streamscan_rs2(init, f) - Apply a function to each element and emit intermediate accumulated valuesfor_each_rs2(f) - Apply a function to each element without accumulating a resultcollect_rs2::<B>() - Collect all items into a collectionfold_rs2 and scan_rs2For examples of accumulating values, see examples/accumulating_values.rs.
// This example demonstrates:
// - Accumulating values using fold_rs2()
// - Emitting intermediate accumulated values using scan_rs2()
// - Applying a function to each element using for_each_rs2()
// - Collecting elements into different collections using collect_rs2()
// See the full code at examples/accumulating_values.rs
map_parallel_rs2(f) - Transform elements in parallel using all available CPU cores (automatic concurrency)map_parallel_with_concurrency_rs2(concurrency, f) - Transform elements in parallel with custom concurrency controlpar_eval_map_rs2(concurrency, f) - Process elements in parallel with bounded concurrency, preserving orderpar_eval_map_unordered_rs2(concurrency, f) - Process elements in parallel without preserving orderpar_join_rs2(concurrency) - Run multiple streams concurrently and combine their outputs| Method | Best For | When to Use | Avoid When |
|---|---|---|---|
| map_parallel_rs2 | CPU-bound work | • Simple parallelization needs • Balanced workloads (similar processing time) • When optimal concurrency = CPU cores • Mathematical calculations, data parsing |
• I/O-bound operations • Memory-intensive tasks • Uneven workloads • When you need fine-tuned concurrency |
| map_parallel_with_concurrency_rs2 | I/O-bound work with sync functions | • Resource-constrained environments • Custom concurrency needs • Network requests, file operations • Mixed workloads (varying processing times) |
• Simple CPU-bound work • When you already have async functions • When automatic concurrency is sufficient |
| par_eval_map_rs2 | Async operations | • Already have async functions • Need custom concurrency control • Want maximum control/performance • API calls, database operations |
• Simple synchronous operations • When order doesn't matter • When simpler methods would suffice |
Start here: Do you have async functions?
par_eval_map_rs2Is your work CPU-bound?
map_parallel_rs2map_parallel_with_concurrency_rs2Need custom concurrency?
map_parallel_with_concurrency_rs2 or par_eval_map_rs2map_parallel_rs2| Workload Type | Recommended Concurrency |
|---|---|
| CPU-bound | num_cpus::get() (automatic in map_parallel_rs2) |
| Network I/O | 50-200 |
| File I/O | 4-16 |
| Database | 10-50 (respect connection pool) |
| Memory-heavy | 1-4 |
Concurrency Guidelines:
num_cpus::get())throttle_rs2(duration) - Emit at most one element per durationdebounce_rs2(duration) - Emit an element after a quiet periodsample_rs2(interval) - Sample at regular intervalstimeout_rs2(duration) - Add timeout to operationstick_rs(period, item) - Create a stream that emits a value at a fixed rateFor examples of time-based operations, see examples/timeout_operations.rs and examples/tick_rs_example.rs.
// This example demonstrates:
// - Adding timeouts to operations using timeout_rs2()
// - Throttling a stream using throttle_rs2()
// - Debouncing a stream using debounce_rs2()
// - Sampling a stream at regular intervals using sample_rs2()
// - Creating a delayed stream using emit_after()
// - Creating a stream that emits values at a fixed rate using tick_rs()
// See the full code at examples/timeout_operations.rs and examples/tick_rs_example.rs
For examples of processing elements in parallel, see examples/processing_elements.rs, and examples/parallel_mapping.rs.
// This example demonstrates:
// - Processing elements in parallel with bounded concurrency using par_eval_map_rs2()
// - Processing elements in parallel without preserving order using par_eval_map_unordered_rs2()
// - Running multiple streams concurrently using par_join_rs2()
// - Transforming elements in parallel using all available CPU cores with map_parallel_rs2()
// - Transforming elements in parallel with custom concurrency using map_parallel_with_concurrency_rs2()
// See the full code at examples/processing_elements.rs and examples/parallel_mapping.rs
recover_rs2(f) - Recover from errors by applying a functionretry_with_policy_rs2(policy, f) - Retry failed operations with a retry policyon_error_resume_next_rs2() - Continue processing after errorsbracket_rs2(acquire, use_fn, release) - Safely acquire and release resourcesbracket_case(acquire, use_fn, release) - Safely acquire and release resources with exit case semantics for streams of Resultbracket_rs2 and bracket_caseFor examples of resource management, see examples/resource_management_bracket.rs, examples/bracket_rs_example.rs, and examples/bracket_case_example.rs.
// This example demonstrates:
// - Safely acquiring and releasing resources using bracket() function
// - Safely acquiring and releasing resources using bracket_rs() extension method
// - Safely acquiring and releasing resources with exit case semantics using bracket_case() extension method
// - Ensuring resources are released even if an error occurs
// See the full code at examples/resource_management_bracket.rs, examples/bracket_rs_example.rs, and examples/bracket_case_example.rs
auto_backpressure_rs2() - Apply automatic backpressureauto_backpressure_with_rs2(config) - Apply automatic backpressure with custom configurationrate_limit_backpressure_rs2(rate) - Apply rate-limited backpressurerate_limit_backpressure(capacity) - Apply back-pressure-aware rate limiting via bounded channel for streams of ResultThe BackpressureConfig struct allows you to customize how backpressure is handled in your streams:
pub struct BackpressureConfig {
pub strategy: BackpressureStrategy,
pub buffer_size: usize,
pub low_watermark: Option<usize>, // Resume at this level
pub high_watermark: Option<usize>, // Pause at this level
}
strategy: Defines the behavior when the buffer reaches capacity:
BackpressureStrategy::DropOldest - Discards the oldest items in the buffer when it's fullBackpressureStrategy::DropNewest - Discards the newest incoming items when the buffer is fullBackpressureStrategy::Block - Blocks the producer until the consumer catches up (default strategy)BackpressureStrategy::Error - Fails immediately when the buffer is fullbuffer_size: The maximum number of items that can be held in the buffer. Default is 100 items.
low_watermark: The buffer level at which to resume processing after being paused. When the buffer level drops below this threshold, a paused producer can resume sending data. Optional, with a default value of 25 (25% of the default buffer size).
high_watermark: The buffer level at which to pause processing. When the buffer level exceeds this threshold, the producer may be paused to allow the consumer to catch up. Optional, with a default value of 75 (75% of the default buffer size).
The default configuration uses:
Block strategyThis creates a system that blocks producers when the buffer is full, pauses when it reaches 75% capacity, and resumes when it drops to 25% capacity.
For examples of custom backpressure, see examples/custom_backpressure.rs and examples/rate_limit_backpressure_example.rs.
// This example demonstrates:
// - Applying automatic backpressure using auto_backpressure_rs2()
// - Configuring custom backpressure strategies using auto_backpressure_with_rs2()
// - Applying rate-limited backpressure using rate_limit_backpressure_rs2()
// - Applying back-pressure-aware rate limiting to streams of Result using rate_limit_backpressure()
// See the full code at examples/custom_backpressure.rs and examples/rate_limit_backpressure_example.rs
RS2 provides built-in support for collecting metrics while processing streams, allowing you to monitor throughput, processing time, and other performance metrics.
with_metrics_rs2(name) - Collect metrics while processing the streamRS2 collects a comprehensive set of metrics to help you monitor and optimize your stream processing:
| Metric | Description | Use Case |
|---|---|---|
name |
Identifier for the stream metrics | Distinguish between multiple streams |
items_processed |
Total number of items processed by the stream | Track overall throughput |
bytes_processed |
Total bytes processed by the stream | Monitor data volume |
processing_time |
Total time spent processing items | Measure processing efficiency |
errors |
Number of errors encountered during processing | Track error rates |
retries |
Number of retry attempts | Monitor retry behavior |
items_per_second |
Throughput in items per second (wall-clock time) | Compare stream performance |
bytes_per_second |
Throughput in bytes per second (wall-clock time) | Measure data throughput |
average_item_size |
Average size of processed items in bytes | Understand data characteristics |
peak_processing_time |
Maximum processing time for any item | Identify processing bottlenecks |
consecutive_errors |
Number of errors without successful processing in between | Detect error patterns |
error_rate |
Ratio of errors to total operations | Monitor stream health |
backpressure_events |
Number of backpressure events | Track backpressure occurrences |
queue_depth |
Current depth of the processing queue | Monitor buffer utilization |
health_thresholds |
Configurable thresholds for determining stream health | Set health monitoring parameters |
The StreamMetrics struct provides several utility methods for working with metrics:
record_item(size_bytes) - Record a processed item with its sizerecord_error() - Record an error occurrencerecord_retry() - Record a retry attemptrecord_processing_time(duration) - Record time spent processingrecord_backpressure() - Record a backpressure eventupdate_queue_depth(depth) - Update the current queue depthis_healthy() - Check if the stream is healthy (low error rate)throughput_items_per_sec() - Calculate items processed per secondthroughput_bytes_per_sec() - Calculate bytes processed per secondthroughput_summary() - Get a formatted summary of throughput metricswith_name(name) - Set a name for the metrics (builder pattern)set_name(name) - Set a name for the metricswith_health_thresholds(thresholds) - Set health thresholds (builder pattern)set_health_thresholds(thresholds) - Set health thresholdsRS2 provides built-in health monitoring for streams through the HealthThresholds configuration:
max_error_rate - Maximum acceptable error rate (default: 0.1 or 10%)max_consecutive_errors - Maximum number of consecutive errors allowed (default: 5)The is_healthy() method uses these thresholds to determine if a stream is healthy. You can customize these thresholds using:
HealthThresholds::default() - Default thresholds (10% error rate, 5 consecutive errors)HealthThresholds::strict() - Strict thresholds for critical systems (1% error rate, 2 consecutive errors)HealthThresholds::relaxed() - Relaxed thresholds for high-throughput systems (20% error rate, 20 consecutive errors)HealthThresholds::custom(max_error_rate, max_consecutive_errors) - Custom thresholdsExample:
// Create metrics with strict health thresholds
let metrics = StreamMetrics::new()
.with_name("critical_stream".to_string())
.with_health_thresholds(HealthThresholds::strict());
// Or update thresholds on existing metrics
metrics.set_health_thresholds(HealthThresholds::custom(0.05, 3));
// Check if the stream is healthy
if !metrics.is_healthy() {
println!("Stream health check failed: error rate = {}, consecutive errors = {}",
metrics.error_rate, metrics.consecutive_errors);
}
For examples of collecting metrics from streams, see examples/with_metrics_example.rs.
// This example demonstrates:
// - Collecting metrics from streams using with_metrics_rs2()
// - Monitoring throughput and processing time
// - Comparing metrics for different stream transformations
// - Collecting metrics for async operations
// See the full code at examples/with_metrics_example.rs
Here's what your stream metrics output could look like (in examples) :
RS2 includes a comprehensive media streaming system with support for file and live streaming, codec operations, chunk processing, and priority-based delivery.
For examples of streaming media from a file, see examples/media_streaming/basic_file_streaming.rs.
// This example demonstrates:
// - Creating a MediaStreamingService
// - Configuring a media stream
// - Starting streaming from a file
// - Processing and displaying the media chunks
// See the full code at examples/media_streaming/basic_file_streaming.rs
For examples of setting up a live stream, see examples/media_streaming/live_streaming.rs.
// This example demonstrates:
// - Creating a MediaStreamingService for live streaming
// - Configuring a live media stream
// - Starting a live stream
// - Processing and displaying the media chunks
// - Monitoring stream metrics in real-time
// See the full code at examples/media_streaming/live_streaming.rs
For examples of configuring a custom codec, see examples/media_streaming/custom_codec.rs.
// This example demonstrates:
// - Creating a custom codec configuration
// - Creating a MediaCodec with the custom configuration
// - Using the codec to encode and decode media data
// - Monitoring codec performance
// See the full code at examples/media_streaming/custom_codec.rs
For examples of handling media stream events, see examples/media_streaming/stream_events.rs.
// This example demonstrates:
// - Creating and handling MediaStreamEvent objects
// - Converting events to UserActivity for analytics
// - Processing events in a stream
// - Implementing a simple event handler
// See the full code at examples/media_streaming/stream_events.rs
For comprehensive documentation on the media streaming components, see the Media Streaming README.
RS2 provides connectors for integrating with external systems like Kafka, databases, and more. Connectors implement the StreamConnector trait:
#[async_trait]
pub trait StreamConnector<T>: Send + Sync
where
T: Send + 'static,
{
type Config: Send + Sync;
type Error: std::error::Error + Send + Sync + 'static;
type Metadata: Send + Sync;
async fn from_source(&self, config: Self::Config) -> Result<RS2Stream<T>, Self::Error>;
async fn to_sink(&self, stream: RS2Stream<T>, config: Self::Config) -> Result<Self::Metadata, Self::Error>;
async fn health_check(&self) -> Result<bool, Self::Error>;
async fn metadata(&self) -> Result<Self::Metadata, Self::Error>;
fn name(&self) -> &'static str;
fn version(&self) -> &'static str;
}
RS2 includes a Kafka connector that allows you to create streams from Kafka topics and send streams to Kafka topics:
// This example demonstrates how to use the Kafka connector to:
// - Create a stream from a Kafka topic
// - Process the stream with RS2 transformations
// - Send the processed stream back to a different Kafka topic
// See the full code at examples/connector_kafka.rs
For the complete example, see examples/connector_kafka.rs.
For a more complex example that demonstrates a complete data streaming pipeline using Kafka and rs2, see examples/kafka_data_pipeline.rs.
// This example demonstrates a complex data streaming pipeline using Kafka and rs2:
// - Data Production: Generate sample user activity data and send it to a Kafka topic
// - Data Consumption: Consume the data from Kafka using rs2 streams
// - Data Processing: Process the data using various rs2 transformations
// - Parsing and validation
// - Enrichment with additional data
// - Aggregation and analytics
// - Filtering and transformation
// - Result Publishing: Send the processed results back to different Kafka topics
// - Parallel Processing: Using par_eval_map_rs2 for efficient processing
// - Backpressure Handling: Automatic backpressure to handle fast producers
// - Error Recovery: Fallback mechanisms for when Kafka is not available
// See the full code at examples/kafka_data_pipeline.rs
You can create your own connectors by implementing the StreamConnector trait. For a complete example of creating a custom connector, see examples/connector_custom.rs.
// This example demonstrates how to:
// - Create a custom connector for a hypothetical message queue
// - Implement the StreamConnector trait
// - Create a stream from the connector
// - Process the stream with RS2 transformations
// - Send the processed stream back to the connector
// See the full code at examples/connector_custom.rs
RS2 makes it easy to build robust, streaming pipelines with ergonomic composition and strong data validation guarantees.
The pipeline builder lets you compose sources, transforms, and sinks in a clear, modular way:
let pipeline = Pipeline::new()
.source(my_source)
.transform(my_transform)
.sink(my_sink)
.build();
You can branch, window, aggregate, and combine streams with ergonomic combinators. See examples/kafka_data_pipeline.rs for a real-world, multi-branch pipeline.
Schema validation is built in. RS2 provides:
SchemaValidator trait for pluggable validation (JSON Schema, Avro, Protobuf, custom)JsonSchemaValidator for validating JSON data using JSON Schema.with_schema_validation_rs2(validator) combinator to filter out invalid items and log errorsSchemaError::ValidationFailed, SchemaError::ParseError, etc.use rs2::schema_validation::JsonSchemaValidator;
use serde_json::json;
let schema = json!({
"type": "object",
"properties": {
"id": {"type": "string"},
"value": {"type": "integer"}
},
"required": ["id", "value"]
});
let validator = JsonSchemaValidator::new("my-schema", schema);
let validated_stream = raw_stream
.with_schema_validation_rs2(validator)
.filter_map(|json| async move { serde_json::from_str::<MyType>(&json).ok() })
.boxed();
See examples/kafka_data_pipeline.rs for a full pipeline with schema validation, branching, analytics, and error handling.
For comprehensive examples of JSON schema validation, see examples/schema_validation_example.rs. This example demonstrates:
Extensibility: You can implement your own SchemaValidator for Avro, Protobuf, or custom formats. The system is async-friendly and ready for integration with schema registries.
A Pipe represents a stream transformation from one type to another. It's a function from Stream[I] to Stream[O] that can be composed with other pipes to create complex stream processing pipelines.
Pipe::new(f) - Create a new pipe from a functionapply(input) - Apply this pipe to a streamcompose(other) - Compose this pipe with another pipemap(f) - Create a pipe that applies the given function to each elementfilter(predicate) - Create a pipe that filters elements based on the predicatecompose(p1, p2) - Compose two pipes togetheridentity() - Identity pipe that doesn't transform the streamFor examples of basic pipe usage, see examples/pipe_basic_usage.rs.
// This example demonstrates:
// - Creating a pipe that doubles each number
// - Applying the pipe to a stream
// See the full code at examples/pipe_basic_usage.rs
For examples of composing pipes, see examples/pipe_composing.rs.
// This example demonstrates:
// - Creating pipes for different transformations
// - Composing pipes using the compose function
// - Composing pipes using the compose method
// See the full code at examples/pipe_composing.rs
For a more complex example of using pipes to process user data, see examples/pipe_user_data_processing.rs.
// This example demonstrates:
// - Creating pipes for filtering active users
// - Creating pipes for transforming User to UserStats
// - Composing pipes to create a processing pipeline
// - Grouping users by login frequency
// See the full code at examples/pipe_user_data_processing.rs
A Queue represents a concurrent queue with a Stream interface for dequeuing and async methods for enqueuing. It supports both bounded and unbounded queues.
Queue::bounded(capacity) - Create a new bounded queue with the given capacityQueue::unbounded() - Create a new unbounded queueenqueue(item) - Enqueue an item into the queuetry_enqueue(item) - Try to enqueue an item without blockingdequeue() - Get a stream for dequeuing itemsclose() - Close the queue, preventing further enqueuescapacity() - Get the capacity of the queue (None for unbounded)is_empty() - Check if the queue is emptylen() - Get the current number of items in the queueFor examples of basic queue usage, see examples/queue_basic_usage.rs.
// This example demonstrates:
// - Creating a bounded queue
// - Enqueuing items
// - Dequeuing items as a stream
// See the full code at examples/queue_basic_usage.rs
For examples of using queues in a producer-consumer pattern, see examples/queue_producer_consumer.rs.
// This example demonstrates:
// - Creating a shared queue
// - Spawning producer and consumer tasks
// - Handling backpressure with bounded queues
// See the full code at examples/queue_producer_consumer.rs