Skip to main content

linkrs_migration/
event.rs

1use crate::plan::{MigrationPlan, MigrationReport};
2
3/// Migration lifecycle notification.
4///
5/// Events are delivered through `EventSubscriptions<MigrationEvent>`.
6/// Callbacks run inline on the migration path with the event borrowed;
7/// they must return quickly, must not block, and a panicking callback is
8/// isolated by the registry so the migration itself is never broken by an
9/// observer.
10#[derive(Debug, Clone)]
11pub enum MigrationEvent {
12    Started { plan: MigrationPlan },
13    StepStarted { step_idx: usize },
14    StepCompleted { step_idx: usize, rows: u64 },
15    Completed { report: MigrationReport },
16    Failed { error: String },
17    RolledBack { report: MigrationReport },
18}
19
20#[cfg(test)]
21mod tests {
22    use super::MigrationEvent;
23    use linkrs_core::event_dispatch::EventSubscriptions;
24    use std::sync::atomic::{AtomicUsize, Ordering};
25    use std::sync::Arc;
26
27    #[test]
28    fn registry_fans_out_to_all_subscribers() {
29        let registry = EventSubscriptions::<MigrationEvent>::new();
30        let hits = Arc::new(AtomicUsize::new(0));
31        for _ in 0..2 {
32            let probe = Arc::clone(&hits);
33            registry.add(Arc::new(move |_| {
34                probe.fetch_add(1, Ordering::SeqCst);
35            }));
36        }
37        registry.dispatch("migration", &MigrationEvent::StepStarted { step_idx: 3 });
38        assert_eq!(hits.load(Ordering::SeqCst), 2);
39    }
40
41    #[test]
42    fn panicking_subscriber_does_not_block_others() {
43        let registry = EventSubscriptions::<MigrationEvent>::new();
44        registry.add(Arc::new(|_| panic!("subscriber boom")));
45        let hits = Arc::new(AtomicUsize::new(0));
46        let probe = Arc::clone(&hits);
47        registry.add(Arc::new(move |_| {
48            probe.fetch_add(1, Ordering::SeqCst);
49        }));
50        registry.dispatch(
51            "migration",
52            &MigrationEvent::Failed {
53                error: "x".to_string(),
54            },
55        );
56        assert_eq!(hits.load(Ordering::SeqCst), 1);
57    }
58}