Skip to main content

sochdb_memory/
enrichment.rs

1use parking_lot::Mutex;
2use std::collections::VecDeque;
3use thiserror::Error;
4
5#[derive(Debug, Clone)]
6pub struct EnrichmentJob {
7    pub namespace: String,
8    pub episode_id: u64,
9    pub text: String,
10}
11
12#[derive(Debug, Error)]
13pub enum EnrichmentError {
14    #[error("enrichment queue full (max {0})")]
15    QueueFull(usize),
16}
17
18#[derive(Debug, Clone)]
19pub struct EnrichmentQueueConfig {
20    pub max_depth: usize,
21}
22
23/// Bounded async enrichment queue (embedding + fact extraction).
24pub struct EnrichmentQueue {
25    max_depth: usize,
26    pending: Mutex<VecDeque<EnrichmentJob>>,
27    processed: Mutex<u64>,
28}
29
30impl EnrichmentQueue {
31    pub fn new(max_depth: usize) -> Self {
32        Self {
33            max_depth,
34            pending: Mutex::new(VecDeque::new()),
35            processed: Mutex::new(0),
36        }
37    }
38
39    pub fn depth(&self) -> usize {
40        self.pending.lock().len()
41    }
42
43    pub fn processed_count(&self) -> u64 {
44        *self.processed.lock()
45    }
46
47    pub fn try_enqueue(&self, job: EnrichmentJob) -> Result<(), EnrichmentError> {
48        let mut q = self.pending.lock();
49        if q.len() >= self.max_depth {
50            return Err(EnrichmentError::QueueFull(self.max_depth));
51        }
52        q.push_back(job);
53        Ok(())
54    }
55
56    pub fn pop(&self) -> Option<EnrichmentJob> {
57        self.pending.lock().pop_front()
58    }
59
60    pub fn mark_processed(&self) {
61        *self.processed.lock() += 1;
62    }
63}