https://github.com/filipdulic/bus-queue
Lock free bounded non blocking pub sub queue
https://github.com/filipdulic/bus-queue
async bus lock-free pub slow-subscribers
Last synced: 2 months ago
JSON representation
Lock free bounded non blocking pub sub queue
- Host: GitHub
- URL: https://github.com/filipdulic/bus-queue
- Owner: filipdulic
- Created: 2018-12-17T20:44:28.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2025-11-04T15:43:37.000Z (7 months ago)
- Last Synced: 2026-03-11T15:51:40.876Z (3 months ago)
- Topics: async, bus, lock-free, pub, slow-subscribers
- Language: Rust
- Size: 261 KB
- Stars: 76
- Watchers: 10
- Forks: 11
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# Lock-free Bounded Non-Blocking Pub-Sub Queue
This is a publish subscribe pattern queue, where the publisher is never blocked by
slow subscribers. The side effect is that slow subscribers will miss messages. The intended
use-case are high throughput streams where receiving the latest message is prioritized over
receiving the entire stream. Market Data Feeds, Live Streams, etc....
The underlying data-structure is a vector of Arc(s) eliminating the use of copies.
## Features
* Lock-Free Write/Read - Lock-Free for Publisher and Lock-Free for Subscribers.
* Bounded - Constant size of memory used, max is **sizeof(MsgObject)*(queue_size + sub_cnt + 1)**.
This is an edge-case where each subscriber is holding a ref to an object while the publisher
has published a full length of queue in the mean time.
* Non-Blocking - The queue never blocks the publisher, slow subscribers miss data proportinal to
their speed.
* Pub-Sub - Every Subscriber that can keep up with the Publisher will recieve all the data the
Publisher publishes.
* **channel** - a raw Pub/Sub channel implementation without the thread synchronisation and futures logic.
* **bus** - an async Pub/Sub queue with **futures::sink::Sink** and **futures::stream::Stream** traits.
**bus::Publisher**, and **channel::Sender** are used to broadcast data to **bus::Subscriber**, and
**channel::Receiver** pools. Subscribers are clone-able such that many threads, or futures, can receive
data simultaneously. The only limitation is that Subscribers have to keep up with the frequency of the
Publisher. If a Subscriber is slow it will drop data.
## Disconnection
The broadcast and receive operations on channels will all return a **Result**
indicating whether the operation succeeded or not. An unsuccessful operation
is normally indicative of the other half of a channel having "hung up" by
being dropped in its corresponding thread.
Once half of a channel has been deallocated, most operations can no longer
continue to make progress, so **Err** will be returned. Many applications
will continue to **unwrap** the results returned from this module,
instigating a propagation of failure among threads if one unexpectedly dies.
# Examples
## Simple raw usage
```rust
extern crate bus_queue;
use bus_queue::flavors::arc_swap::bounded;
let (tx, rx) = bounded(10);
(1..15).for_each(|x| tx.broadcast(x).unwrap());
let received: Vec = rx.map(|x| *x).collect();
// Test that only the last 10 elements are in the received list.
let expected: Vec = (5..15).collect();
assert_eq!(expected, received);
```
## Simple async usage
```rust
use bus_queue::flavors::arc_swap::async_bounded;
use futures::executor::block_on;
use futures::stream;
use futures::StreamExt;
let (publisher, subscriber1) = async_bounded(10);
let subscriber2 = subscriber1.clone();
block_on(async move {
stream::iter(1..15)
.map(|i| Ok(i))
.forward(publisher)
.await
.unwrap();
});
let received1: Vec = block_on(async { subscriber1.map(|x| *x).collect().await });
let received2: Vec = block_on(async { subscriber2.map(|x| *x).collect().await });
// Test that only the last 10 elements are in the received list.
let expected = (5..15).collect::>();
assert_eq!(received1, expected);
assert_eq!(received2, expected);
```