use ruststream::OutSlot;
use ruststream_lapin::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Deserialize, Serialize, Outgoing)]
#[outgoing(name = "meters")]
struct MeterTick {
meter: String,
kwh: u64,
billing: bool,
}
#[derive(Debug, PartialEq, Deserialize, Serialize, Outgoing)]
#[outgoing(name = "readings")]
struct Reading {
meter: String,
kwh: u64,
}
#[derive(OutSlot)]
#[publishes(Reading)]
struct Readings;
#[subscriber(RabbitQueue::new("meters"))]
async fn record(
tick: &MeterTick,
Out(readings): Out<impl Publisher<Options = LapinPublishOptions>, Readings>,
) -> HandlerOutcome {
let reading = Reading {
meter: tick.meter.clone(),
kwh: tick.kwh,
};
let sent = if tick.billing {
readings.message(&reading).persistent(true).publish().await
} else {
readings.message(&reading).publish().await
};
if sent.is_err() {
return HandlerOutcome::retry();
}
HandlerOutcome::ack()
}
#[ruststream::app]
fn app() -> impl App {
RustStream::new(AppInfo::new("metering", "0.1.0")).with_broker(
LapinBroker::new("amqp://localhost:5672"),
|b| {
b.include(record)
.out(Readings, Publish::default().persistent(false))
.build();
},
)
}
#[cfg(test)]
mod tests {
use std::error::Error;
use ruststream::testing::TestApp;
use ruststream_lapin::prelude::*;
use super::{MeterTick, Readings, app};
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn a_billing_reading_is_persistent() -> Result<(), Box<dyn Error>> {
let tb = TestApp::start(app()).await?;
tb.broker::<LapinBroker>()
.message(&MeterTick {
meter: "m-1".into(),
kwh: 12,
billing: true,
})
.publish()
.await?;
tb.out::<Readings>()
.assert_called_once()
.with_options(&LapinPublishOptions {
persistent: Some(true),
..LapinPublishOptions::default()
});
tb.shutdown().await?;
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn a_live_reading_takes_the_transient_policy() -> Result<(), Box<dyn Error>> {
let tb = TestApp::start(app()).await?;
tb.broker::<LapinBroker>()
.message(&MeterTick {
meter: "m-1".into(),
kwh: 12,
billing: false,
})
.publish()
.await?;
tb.out::<Readings>()
.assert_called_once()
.assert_options_default();
tb.shutdown().await?;
Ok(())
}
}