use std::future::{Future, ready};
use ruststream::memory::prelude::*;
use serde::Deserialize;
#[derive(Debug, Deserialize, schemars::JsonSchema)]
struct Order {
id: u64,
}
#[subscriber("orders")]
async fn handle(order: &Order) -> HandlerOutcome {
println!("got order {}", order.id);
HandlerOutcome::ack()
}
#[subscriber("orders")]
async fn with_context(order: &Order, ctx: &mut Context<'_>) -> HandlerOutcome {
if let Some(id) = ctx.headers().correlation_id() {
println!("order {} correlates to {id}", order.id);
}
HandlerOutcome::ack()
}
#[subscriber]
async fn audit(order: &Order) -> HandlerOutcome {
println!("auditing order {}", order.id);
HandlerOutcome::ack()
}
#[subscriber(MemorySource)]
async fn archive(order: &Order) -> HandlerOutcome {
println!("archiving order {}", order.id);
HandlerOutcome::ack()
}
#[subscriber("orders")]
async fn settle(orders: &[Order]) -> HandlerOutcome {
println!("settling {} orders", orders.len());
HandlerOutcome::ack()
}
#[derive(Deserialized)]
struct Frame<'a>(&'a [u8]);
#[subscriber("frames")]
async fn ingest(frames: &[Frame<'_>]) -> HandlerOutcome {
let bytes: usize = frames.iter().map(|frame| frame.0.len()).sum();
println!("ingesting {} frames ({bytes} bytes)", frames.len());
HandlerOutcome::ack()
}
#[subscriber("orders", workers(16))]
async fn fan_out(order: &Order) -> HandlerOutcome {
println!("processing order {}", order.id);
HandlerOutcome::ack()
}
#[subscriber("orders", workers(16, by_key))]
async fn per_customer(order: &Order) -> HandlerOutcome {
println!("processing order {}", order.id);
HandlerOutcome::ack()
}
#[subscriber("orders")]
async fn reconcile(orders: &[Order]) -> Vec<HandlerOutcome> {
orders
.iter()
.map(|order| {
if order.id == 0 {
HandlerOutcome::retry()
} else {
HandlerOutcome::ack()
}
})
.collect()
}
#[subscriber]
async fn drain(orders: &[Order]) -> HandlerOutcome {
println!("draining {} orders", orders.len());
HandlerOutcome::ack()
}
#[subscriber]
async fn bill(order: &Order) -> HandlerOutcome {
println!("billing order {}", order.id);
HandlerOutcome::ack()
}
#[allow(clippy::items_after_statements)]
#[ruststream::app]
fn app() -> RustStream {
let shard = 7;
RustStream::new(AppInfo::new("subscribers", "0.1.0")).with_broker(MemoryBroker::new(), |b| {
b.include(handle);
b.include(with_context);
b.include(audit.name(format!("audit-{shard}")));
b.include(archive.name("archive"));
b.include(settle.batch(nonzero!(64)));
b.include(ingest.batch(nonzero!(32)));
b.include(reconcile.batch(nonzero!(64)));
b.include(drain.name("orders").batch(nonzero!(128)));
b.include(
bill.name("orders")
.workers(nonzero!(4))
.on_failure(FailurePolicies::default().with_decode(FailurePolicy::Skip)),
);
b.include(fan_out);
b.include(per_customer);
struct Inline;
impl Handle<Order> for Inline {
fn handle(
&self,
order: &Order,
_outs: &(),
_ctx: &mut Context<'_>,
) -> impl Future<Output = Result<(), HandlerOutcome>> {
println!("got order {}", order.id);
ready(Ok(()))
}
}
b.include(subscriber("orders", Inline).build());
})
}