use std::{mem::take, sync::Arc};
use reifydb_runtime::sync::mutex::Mutex;
use crate::lifecycle::task::LifecycleTask;
#[derive(Clone)]
pub struct LifecycleRegistry {
tasks: Arc<Mutex<Vec<Box<dyn LifecycleTask>>>>,
}
impl LifecycleRegistry {
pub fn new() -> Self {
Self {
tasks: Arc::new(Mutex::new(Vec::new())),
}
}
pub fn register(&self, task: Box<dyn LifecycleTask>) {
self.tasks.lock().push(task);
}
pub fn take(&self) -> Vec<Box<dyn LifecycleTask>> {
take(&mut *self.tasks.lock())
}
pub fn is_empty(&self) -> bool {
self.tasks.lock().is_empty()
}
pub fn len(&self) -> usize {
self.tasks.lock().len()
}
}
impl Default for LifecycleRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use reifydb_value::value::duration::Duration;
use super::*;
use crate::lifecycle::{class::RetentionClass, progress::Progress};
struct CountingTask {
remaining: usize,
slices: Arc<Mutex<usize>>,
}
impl LifecycleTask for CountingTask {
fn name(&self) -> &'static str {
"counting"
}
fn interval(&self) -> Duration {
Duration::from_seconds(1).unwrap()
}
fn classes(&self) -> &'static [RetentionClass] {
&[]
}
fn run_slice(&mut self) -> Progress {
*self.slices.lock() += 1;
if self.remaining > 0 {
self.remaining -= 1;
}
if self.remaining == 0 {
Progress::Exhausted
} else {
Progress::Yielded
}
}
}
#[test]
fn registry_collects_and_drains_tasks() {
let registry = LifecycleRegistry::new();
assert!(registry.is_empty(), "a fresh registry holds no tasks");
registry.register(Box::new(CountingTask {
remaining: 1,
slices: Arc::new(Mutex::new(0)),
}));
assert!(!registry.is_empty(), "a registered task must be visible before the subsystem drains it");
let taken = registry.take();
assert_eq!(taken.len(), 1, "take must hand every registered task to the subsystem exactly once");
assert!(registry.is_empty(), "take must empty the registry so the subsystem is the sole owner");
}
#[test]
fn run_slice_reports_yielded_until_work_is_exhausted() {
let slices = Arc::new(Mutex::new(0usize));
let mut task = CountingTask {
remaining: 3,
slices: slices.clone(),
};
assert_eq!(task.run_slice(), Progress::Yielded, "first of three slices still has work left");
assert_eq!(task.run_slice(), Progress::Yielded, "second slice still has work left");
assert_eq!(task.run_slice(), Progress::Exhausted, "the final slice must report Exhausted");
assert_eq!(*slices.lock(), 3, "each slice must run exactly once");
}
}