aster_forge_mail/
component.rs1use std::future::Future;
10
11use aster_forge_runtime::{RuntimeComponentBundleRegistration, RuntimeComponentKind};
12
13use crate::MAIL_OUTBOX_COMPONENT;
14pub const MAIL_OUTBOX_DRAIN_SHUTDOWN_PHASE: &str = "mail_outbox_drain";
16
17pub fn mail_outbox_component<T, F, Fut>(
24 resources: T,
25 drain: F,
26) -> RuntimeComponentBundleRegistration<aster_forge_runtime::ShutdownResourceComponent<T>>
27where
28 T: Send + 'static,
29 F: FnOnce(T) -> Fut + Send + Sync + 'static,
30 Fut: Future<Output = Result<(), String>> + Send + 'static,
31{
32 aster_forge_runtime::shutdown_resource_component_after(
33 MAIL_OUTBOX_COMPONENT,
34 RuntimeComponentKind::Mail,
35 MAIL_OUTBOX_DRAIN_SHUTDOWN_PHASE,
36 &[aster_forge_tasks::BACKGROUND_TASKS_COMPONENT],
37 resources,
38 drain,
39 )
40}
41
42#[cfg(test)]
43mod tests {
44 use std::sync::{
45 Arc,
46 atomic::{AtomicUsize, Ordering},
47 };
48
49 use aster_forge_runtime::RuntimeComponentBundle;
50
51 use super::{MAIL_OUTBOX_COMPONENT, MAIL_OUTBOX_DRAIN_SHUTDOWN_PHASE, mail_outbox_component};
52
53 #[test]
54 fn mail_outbox_component_registers_standard_shutdown_dependency() {
55 let registry = aster_forge_runtime::RuntimeComponentRegistry::configured(|registry| {
56 mail_outbox_component((), |()| async { Ok(()) }).register(registry);
57 });
58
59 let descriptor = registry
60 .descriptor(MAIL_OUTBOX_COMPONENT)
61 .expect("mail outbox component should be registered");
62 assert_eq!(
63 descriptor.kind,
64 aster_forge_runtime::RuntimeComponentKind::Mail
65 );
66 assert_eq!(
67 descriptor.dependencies,
68 vec![aster_forge_tasks::BACKGROUND_TASKS_COMPONENT]
69 );
70 assert_eq!(
71 descriptor
72 .shutdown
73 .first()
74 .expect("mail outbox shutdown should be registered")
75 .phase_name,
76 MAIL_OUTBOX_DRAIN_SHUTDOWN_PHASE
77 );
78 }
79
80 #[tokio::test]
81 async fn mail_outbox_component_consumes_resource_once_during_shutdown() {
82 let calls = Arc::new(AtomicUsize::new(0));
83 let calls_for_drain = calls.clone();
84 let mut registry = aster_forge_runtime::RuntimeComponentRegistry::new();
85 registry.register_bundle(mail_outbox_component(7usize, move |resource| {
86 let calls = calls_for_drain.clone();
87 async move {
88 assert_eq!(resource, 7);
89 calls.fetch_add(1, Ordering::SeqCst);
90 Ok(())
91 }
92 }));
93 let report = registry.shutdown().await;
94
95 assert!(!report.has_failures());
96 assert_eq!(calls.load(Ordering::SeqCst), 1);
97 }
98}