use std::sync::Arc;
use async_trait::async_trait;
use tracing::{debug, error, info, warn};
use crate::handler::NStreamsHandler;
use crate::namespace::{Namespace, StreamNamespace};
use crate::store::EventStore;
use crate::stream::{ReadStreamBackend, WriteQueueBackend};
pub struct StreamWorker<S, Q, R> {
store: Arc<S>,
read_stream: Arc<R>,
handler: Arc<NStreamsHandler<S, R>>,
_queue: std::marker::PhantomData<Q>,
}
impl<S, Q, R> StreamWorker<S, Q, R>
where
S: EventStore + 'static,
Q: WriteQueueBackend + 'static,
R: ReadStreamBackend + 'static,
{
pub fn new(
store: S,
_queue: Q,
read_stream: R,
handler: NStreamsHandler<S, R>,
) -> Self {
Self {
store: Arc::new(store),
read_stream: Arc::new(read_stream),
handler: Arc::new(handler),
_queue: std::marker::PhantomData,
}
}
pub async fn run<QC: QueueConsumer>(&self, mut consumer: QC) -> crate::Result<()> {
info!("stream worker started");
while let Some(delivery) = consumer.next().await {
match delivery {
Ok(message) => {
if let Err(error) = self
.process_message(
&message.namespace,
&message.payload,
message.filter_value.as_deref(),
)
.await
{
error!(namespace = %message.namespace, %error, "failed to process queue message");
}
}
Err(error) => {
warn!(%error, "queue consumer error");
}
}
}
Ok(())
}
async fn process_message(
&self,
namespace: &str,
payload: &[u8],
filter_value: Option<&str>,
) -> crate::Result<()> {
let namespace = crate::namespace::StreamNamespace::from(namespace);
StreamNamespace::validate(namespace.as_str())?;
self.store.ensure_namespace(&namespace).await?;
let event = self
.store
.persist_next(&namespace, payload, filter_value)
.await?;
debug!(
namespace = namespace.as_str(),
version = event.version,
"persisted event"
);
if self.handler.is_read_stream_ready(&namespace).await {
self.read_stream.publish_to_stream(&event).await?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct QueueMessage {
pub namespace: String,
pub payload: Vec<u8>,
pub filter_value: Option<String>,
}
#[async_trait]
pub trait QueueConsumer: Send {
async fn next(&mut self) -> Option<std::result::Result<QueueMessage, crate::Error>>;
}