Skip to main content

runifold_core/
journal.rs

1use std::sync::{Arc, Mutex, MutexGuard};
2
3use thiserror::Error;
4
5use crate::RunEvent;
6
7/// A journal storage failure.
8#[derive(Clone, Debug, Error, Eq, PartialEq)]
9#[error("journal error: {message}")]
10pub struct JournalError {
11    /// Safe failure explanation.
12    pub message: String,
13}
14
15/// Receives immutable runtime events.
16pub trait Journal: Send + Sync {
17    /// Records one event.
18    ///
19    /// # Errors
20    ///
21    /// Returns [`JournalError`] when the backing store cannot durably accept
22    /// the event.
23    fn record(&self, event: &RunEvent) -> Result<(), JournalError>;
24}
25
26/// A cloneable in-memory journal for tests and ephemeral runs.
27#[derive(Clone, Debug, Default)]
28pub struct InMemoryJournal {
29    events: Arc<Mutex<Vec<RunEvent>>>,
30}
31
32impl InMemoryJournal {
33    /// Creates an empty journal.
34    pub fn new() -> Self {
35        Self::default()
36    }
37
38    /// Returns a snapshot of all recorded events.
39    pub fn events(&self) -> Vec<RunEvent> {
40        self.lock_events().clone()
41    }
42
43    /// Returns the number of recorded events.
44    pub fn len(&self) -> usize {
45        self.lock_events().len()
46    }
47
48    /// Returns whether no events have been recorded.
49    pub fn is_empty(&self) -> bool {
50        self.lock_events().is_empty()
51    }
52
53    /// Appends an event to the in-memory log.
54    pub fn push(&self, event: RunEvent) {
55        self.lock_events().push(event);
56    }
57
58    fn lock_events(&self) -> MutexGuard<'_, Vec<RunEvent>> {
59        self.events
60            .lock()
61            .unwrap_or_else(std::sync::PoisonError::into_inner)
62    }
63}
64
65impl Journal for InMemoryJournal {
66    fn record(&self, event: &RunEvent) -> Result<(), JournalError> {
67        self.push(event.clone());
68        Ok(())
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::{InMemoryJournal, Journal};
75    use crate::{EventFactory, LifecycleEvent, RunEventKind, RunId};
76
77    #[test]
78    fn clones_share_the_same_event_log() {
79        let journal = InMemoryJournal::new();
80        let clone = journal.clone();
81        let event = EventFactory::new(RunId::new(), None)
82            .emit(RunEventKind::Lifecycle(LifecycleEvent::Started), None);
83
84        journal.record(&event).unwrap();
85
86        assert_eq!(clone.events(), vec![event]);
87    }
88}