| Crates.io | tokio-sticky-channel |
| lib.rs | tokio-sticky-channel |
| version | 0.1.3 |
| created_at | 2025-07-17 05:58:19.278558+00 |
| updated_at | 2025-07-17 08:28:56.519232+00 |
| description | Sticky channel pattern for Tokio - routes messages to specific receivers based on ID hash for consistent message delivery |
| homepage | https://github.com/devashishdxt/tokio-sticky-channel |
| repository | https://github.com/devashishdxt/tokio-sticky-channel |
| max_upload_size | |
| id | 1757104 |
| size | 77,731 |
A sticky channel implementation for Tokio that routes messages to specific receivers based on ID hashing.
This crate provides message passing channels where messages with the same ID are consistently delivered to the same receiver. This is useful for workload distribution scenarios where you need to ensure that related messages are processed by the same consumer for ordering guarantees or stateful processing.
async and non-blocking receive operationstokio::select!use tokio_sticky_channel::unbounded_sticky_channel;
use std::num::NonZeroUsize;
#[tokio::main]
async fn main() {
// Create an unbounded sticky channel with 3 consumers
let (sender, mut receivers) = unbounded_sticky_channel::<&str, i32>(
NonZeroUsize::new(3).unwrap()
);
// Send messages with IDs - same ID always goes to same receiver
sender.send("user-123", 42).unwrap();
sender.send("user-456", 24).unwrap();
sender.send("user-123", 84).unwrap(); // Same receiver as first message
// Receive messages from different consumers
for receiver in &mut receivers {
if let Some(message) = receiver.try_recv().ok() {
println!("Received: {}", message);
}
}
}
use tokio_sticky_channel::sticky_channel;
use std::num::NonZeroUsize;
#[tokio::main]
async fn main() {
// Create a bounded sticky channel with 3 consumers and capacity of 100 per channel
let (sender, mut receivers) = sticky_channel::<&str, i32>(
NonZeroUsize::new(3).unwrap(),
100
);
// Send messages with IDs - will block if target channel is full
sender.send("user-123", 42).await.unwrap();
sender.send("user-456", 24).await.unwrap();
// Try to send without blocking - returns error if channel is full
match sender.try_send("user-789", 99) {
Ok(_) => println!("Message sent successfully"),
Err(e) => println!("Failed to send: {}", e),
}
// Drop sender to close channels
drop(sender);
// Receive messages from all receivers
for receiver in &mut receivers {
while let Some(message) = receiver.recv().await {
println!("Received: {}", message);
}
}
}
The sticky channel uses consistent hashing to route messages:
hash(id) % num_consumers to determine the target receiverLicensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.