use std::error::Error;
use std::future::{Future, ready};
use std::time::Duration;
use ruststream::memory::prelude::*;
use serde::{Deserialize, Serialize};
use tokio::time::sleep;
#[derive(Debug, Serialize, Deserialize, schemars::JsonSchema)]
struct Job {
id: u64,
}
impl OutgoingDestination for Job {
type Form = CallerName;
}
impl MessageHeaders for Job {
type Contract = NoHeaders;
}
struct Record;
impl Handle<Job> for Record {
fn handle(
&self,
entry: &Job,
_outs: &(),
_ctx: &mut Context<'_>,
) -> impl Future<Output = Result<(), HandlerOutcome>> {
println!("audit: entry {}", entry.id);
ready(Ok(()))
}
}
struct Work;
impl Handle<Job, (), (), MemoryContext> for Work {
async fn handle(
&self,
job: &Job,
_outs: &(),
ctx: &mut Context<'_, MemoryContext>,
) -> Result<(), HandlerOutcome> {
if job.id == 999 {
if ctx
.context(SeekHandle)
.seek(MemoryPosition::sequence(3))
.await
.is_err()
{
return Err(HandlerOutcome::retry());
}
return Ok(());
}
println!("jobs: processed {}", job.id);
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let broker = MemoryBroker::retaining(Retention::Messages(nonzero!(64)));
let ingress = broker.publisher();
for id in 1..=2u64 {
ingress.message(&Job { id }).to("audit").publish().await?;
}
let app = RustStream::new(AppInfo::new("seek-demo", "0.1.0")).with_broker(broker, |b| {
b.include(subscriber(MemorySource::new("jobs"), Work).build());
b.include(
subscriber(MemorySource::new("audit"), Record)
.start_at(MemoryPosition::start())
.build(),
);
});
let running = app.start().await?;
for id in [1, 999, 3, 4] {
ingress.message(&Job { id }).to("jobs").publish().await?;
}
sleep(Duration::from_millis(100)).await;
running.shutdown().await?;
println!("ok: replayed the audit history and skipped the poisoned region");
Ok(())
}