Skip to content

rust.unbounded_channel

Stability Medium

Detects usage of unbounded channels that can cause memory exhaustion.

Unbounded channels grow without limit:

  • Memory exhaustion — If sender outpaces receiver, queue grows forever
  • OOM crash — Eventually the process is killed
  • Hidden backpressure — No signal to slow down producers
  • Latency spikes — Queue grows, items wait longer

Bounded channels provide natural backpressure.

// ❌ Before
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
// Sender can overwhelm receiver
for item in items {
tx.send(item).unwrap(); // Never blocks
}
// ✅ After
let (tx, rx) = tokio::sync::mpsc::channel(1000); // Bounded
for item in items {
tx.send(item).await.unwrap(); // Blocks when full
}
  • unbounded_channel() from tokio or std
  • crossbeam::channel::unbounded()
  • flume::unbounded()

Unfault converts to bounded channel with configurable capacity.

// Known finite producers
let (tx, rx) = unbounded_channel();
for i in 0..10 { // Fixed, small count
tx.send(i).unwrap();
}
// Command channels where blocking is worse
// (but document the risk)
let (cmd_tx, cmd_rx) = unbounded_channel(); // Commands are rare
// High throughput: larger buffer
let (tx, rx) = channel(10_000);
// Low latency: smaller buffer (backpressure sooner)
let (tx, rx) = channel(100);
// Memory constrained: calculate based on item size
let capacity = MAX_MEMORY / std::mem::size_of::<Item>();
let (tx, rx) = channel(capacity);