ruststream 0.4.0

Async messaging framework for Rust: broker-agnostic traits, router, codecs, and a conformance harness for broker authors.
Documentation

RustStream connects your service to a message broker through a small set of generic traits, then gives you a router, middleware, codecs, and tooling on top. The core depends on no broker, so each broker is an independent crate held to one contract; broker-specific configuration never leaks into the framework.

Features

  • Broker-agnostic core. Just traits and types, zero broker dependencies. Brokers are separate crates, and the contract is checked by a conformance harness.
  • Fully async on tokio. No blocking APIs in the public surface.
  • Subscribers are Streams, not callbacks. Back-pressure comes for free.
  • Ack consumes self. Double-ack is a compile error.
  • Pluggable codecs: JSON, MessagePack, and CBOR behind cargo features.
  • Zero-boilerplate binaries. #[ruststream::app] generates main; the ruststream CLI scaffolds projects, runs them, and generates the AsyncAPI document.
  • AsyncAPI 3.0 and Prometheus metrics, served from your own HTTP stack.
  • Colored console logging behind the logging feature; the generated CLI installs it on run, with verbosity driven by RUST_LOG.
  • Capability traits for optional features (batch subscribe, transactions, request-reply, partitioning); a broker implements only what it supports.

Install

[dependencies]
ruststream = { version = "0.4", features = ["macros", "memory", "json"] }
serde = { version = "1", features = ["derive"] }
schemars = "1"

The CLI ships with the crate behind the cli feature:

cargo install ruststream --features cli

Write a service

use ruststream::memory::MemoryBroker;
use ruststream::runtime::{AppInfo, HandlerResult, RustStream};
use ruststream::subscriber;
use schemars::JsonSchema;
use serde::Deserialize;

#[derive(Debug, Deserialize, JsonSchema)]
struct Order {
    id: u64,
}

#[subscriber("orders")]
async fn handle(order: &Order) -> HandlerResult {
    println!("got order {}", order.id);
    HandlerResult::Ack
}

#[ruststream::app]
fn app() -> RustStream {
    RustStream::new(AppInfo::new("orders", "0.1.0"))
        .with_broker(MemoryBroker::new(), |b| b.include(handle))
}

#[ruststream::app] generates main, so there is no runtime boilerplate.

Run it

ruststream run                 # start the service (or: cargo run -- run)
ruststream asyncapi gen        # print the AsyncAPI document
ruststream new my-service      # scaffold a new project

Test it

Unit-test handlers against the in-memory broker, with no external service. It does core routing only, so you assert on handler behaviour, middleware, and decoding exactly as in production. See the testing guide.

Documentation

Ecosystem

Concrete brokers live in their own crates and pull ruststream from crates.io.

Minimum supported Rust version

The MSRV is 1.85 (edition 2024, native async fn in trait). CI builds the crate on every stable toolchain from 1.85 up to current stable, so any floor in that range works.

The policy:

  • The published rust-version stays at the floor. Raising it is a breaking change (a minor version bump pre-1.0) and is reviewed against the broker crates' client requirements at each minor release.
  • Broker crates (ruststream-nats, ...) may require a newer toolchain than the core when their underlying clients do; cargo allows a dependent crate to have a stricter floor than its dependency. Check the broker crate's own rust-version for its floor.

Contributing

just check    # fmt, clippy, and feature checks
just test     # the test suite

License

Licensed under the Apache-2.0 license.

Inspired by FastStream.