#![cfg_attr(not(test), allow(dead_code, unused_imports))]
use std::time::Duration;
use ruststream::memory::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Deserialize, Serialize, schemars::JsonSchema)]
struct Order {
id: u64,
}
impl OutgoingDestination for Order {
type Form = CallerName;
}
impl MessageHeaders for Order {
type Contract = NoHeaders;
}
async fn charge(order: &Order) {
tokio::time::sleep(Duration::from_secs(1)).await;
tracing::info!(order.id, "charged");
}
struct Bill;
impl Handle<Order> for Bill {
async fn handle(
&self,
order: &Order,
_outs: &(),
_ctx: &mut Context<'_>,
) -> Result<(), HandlerOutcome> {
charge(order).await;
Ok(())
}
}
mod pool {
use std::error::Error;
use futures::future::join_all;
use ruststream::memory::prelude::*;
use ruststream::testing::TestApp;
use tokio::time::Instant;
use super::{Bill, Order};
fn app() -> impl App {
RustStream::new(AppInfo::new("billing", "0.1.0")).with_broker(MemoryBroker::new(), |b| {
b.include(subscriber("orders", Bill).workers(nonzero!(4)).build());
})
}
#[tokio::test]
async fn four_orders_are_charged_together() -> Result<(), Box<dyn Error>> {
tokio::time::pause();
let tb = TestApp::start(app()).await?;
let broker = tb.broker::<MemoryBroker>();
let orders: Vec<Order> = (1..=4).map(|id| Order { id }).collect();
let started = Instant::now();
for published in join_all(
orders
.iter()
.map(|order| broker.message(order).to("orders").publish()),
)
.await
{
published?;
}
assert_eq!(started.elapsed().as_secs(), 1);
broker
.subscriber("orders")
.assert_called(4)
.settled(HandlerOutcome::ack());
Ok(())
}
}
mod by_key {
use std::error::Error;
use futures::future::join_all;
use ruststream::HeaderMap;
use ruststream::memory::PARTITION_KEY_HEADER;
use ruststream::memory::prelude::*;
use ruststream::testing::TestApp;
use tokio::time::Instant;
use super::{Bill, Order};
fn app() -> impl App {
RustStream::new(AppInfo::new("billing", "0.1.0")).with_broker(MemoryBroker::new(), |b| {
b.include(
subscriber("orders", Bill)
.workers_by_key(nonzero!(4))
.build(),
);
})
}
#[tokio::test]
async fn one_customer_waits_for_its_own_orders_only() -> Result<(), Box<dyn Error>> {
tokio::time::pause();
let tb = TestApp::start(app()).await?;
let broker = tb.broker::<MemoryBroker>();
let orders: Vec<(Order, HeaderMap)> = [(1, "alice"), (2, "bob"), (3, "alice"), (4, "bob")]
.into_iter()
.map(|(id, customer)| {
let mut headers = HeaderMap::new();
headers.insert(PARTITION_KEY_HEADER, customer);
(Order { id }, headers)
})
.collect();
let started = Instant::now();
for published in join_all(orders.iter().map(|(order, headers)| {
broker
.message(order)
.with_headers(headers.clone())
.to("orders")
.publish()
}))
.await
{
published?;
}
assert_eq!(started.elapsed().as_secs(), 2);
broker
.subscriber("orders")
.assert_called(4)
.settled(HandlerOutcome::ack());
Ok(())
}
}
fn main() {}