aster_forge_config/notification/
runtime.rs1use std::future::Future;
2use tokio_util::sync::CancellationToken;
3
4use crate::Result;
5
6use super::message::{ConfigNotificationSource, ConfigReloadMessage, ConfigReloadWorkerConfig};
7use super::notifier::SharedConfigChangeNotifier;
8use super::supervisor::{
9 ConfigReloadObserver, ConfigSyncConnectionObserver, run_config_reload_supervisor,
10 run_config_reload_supervisor_with_observers, run_config_reload_worker,
11 run_config_reload_worker_with_observer,
12};
13
14#[derive(Clone)]
21pub struct ConfigSyncRuntime {
22 namespace: String,
23 runtime_id: String,
24 notifier: Option<SharedConfigChangeNotifier>,
25}
26
27impl ConfigSyncRuntime {
28 pub fn new(
30 namespace: impl Into<String>,
31 runtime_id: impl Into<String>,
32 notifier: impl Into<SharedConfigChangeNotifier>,
33 ) -> Self {
34 Self {
35 namespace: namespace.into(),
36 runtime_id: runtime_id.into(),
37 notifier: Some(notifier.into()),
38 }
39 }
40
41 pub fn disabled(namespace: impl Into<String>) -> Self {
43 Self::disabled_with_runtime_id(namespace, aster_forge_utils::id::new_runtime_id())
44 }
45
46 pub fn disabled_with_runtime_id(
48 namespace: impl Into<String>,
49 runtime_id: impl Into<String>,
50 ) -> Self {
51 Self {
52 namespace: namespace.into(),
53 runtime_id: runtime_id.into(),
54 notifier: None,
55 }
56 }
57
58 pub fn disabled_for_test(namespace: impl Into<String>) -> Self {
60 Self::disabled_with_runtime_id(namespace, "test-runtime")
61 }
62
63 pub fn with_notifier_for_test(
65 namespace: impl Into<String>,
66 runtime_id: impl Into<String>,
67 notifier: impl Into<SharedConfigChangeNotifier>,
68 ) -> Self {
69 Self::new(namespace, runtime_id, notifier)
70 }
71
72 #[must_use]
74 pub fn namespace(&self) -> &str {
75 &self.namespace
76 }
77
78 #[must_use]
80 pub fn runtime_id(&self) -> &str {
81 &self.runtime_id
82 }
83
84 #[must_use]
86 pub fn notifier(&self) -> Option<&SharedConfigChangeNotifier> {
87 self.notifier.as_ref()
88 }
89
90 #[must_use]
92 pub fn enabled(&self) -> bool {
93 self.notifier.is_some()
94 }
95
96 #[must_use]
98 pub fn worker_config(&self) -> ConfigReloadWorkerConfig {
99 ConfigReloadWorkerConfig::new(self.namespace(), self.runtime_id())
100 }
101
102 pub async fn publish_reload(
108 &self,
109 keys: impl IntoIterator<Item = impl Into<String>>,
110 source: ConfigNotificationSource,
111 ) -> Result<()> {
112 let Some(notifier) = self.notifier() else {
113 return Ok(());
114 };
115
116 notifier
117 .publish_reload(ConfigReloadMessage::new(
118 self.namespace(),
119 self.runtime_id(),
120 keys,
121 source,
122 ))
123 .await
124 }
125
126 pub async fn run_reload_subscription<F, Fut>(
137 &self,
138 shutdown: CancellationToken,
139 reload: F,
140 ) -> Result<()>
141 where
142 F: FnMut(ConfigReloadMessage) -> Fut,
143 Fut: Future<Output = Result<()>>,
144 {
145 let Some(notifier) = self.notifier().cloned() else {
146 shutdown.cancelled().await;
147 return Ok(());
148 };
149 run_config_reload_worker(notifier, self.worker_config(), shutdown, reload).await
150 }
151
152 pub async fn run_reload_subscription_with_observer<F, Fut>(
158 &self,
159 shutdown: CancellationToken,
160 reload: F,
161 observer: Option<&dyn ConfigReloadObserver>,
162 ) -> Result<()>
163 where
164 F: FnMut(ConfigReloadMessage) -> Fut,
165 Fut: Future<Output = Result<()>>,
166 {
167 let Some(notifier) = self.notifier().cloned() else {
168 shutdown.cancelled().await;
169 return Ok(());
170 };
171 run_config_reload_worker_with_observer(
172 notifier,
173 self.worker_config(),
174 shutdown,
175 reload,
176 observer,
177 )
178 .await
179 }
180
181 pub async fn run_reload_subscription_with_reconcile<R, RFut, F, Fut>(
193 &self,
194 shutdown: CancellationToken,
195 reconcile: R,
196 reload: F,
197 ) -> Result<()>
198 where
199 R: FnMut() -> RFut,
200 RFut: Future<Output = Result<()>>,
201 F: FnMut(ConfigReloadMessage) -> Fut,
202 Fut: Future<Output = Result<()>>,
203 {
204 let Some(notifier) = self.notifier().cloned() else {
205 shutdown.cancelled().await;
206 return Ok(());
207 };
208 run_config_reload_supervisor(notifier, self.worker_config(), shutdown, reconcile, reload)
209 .await
210 }
211
212 pub async fn run_reload_subscription_with_reconcile_and_observers<R, RFut, F, Fut>(
218 &self,
219 shutdown: CancellationToken,
220 reconcile: R,
221 reload: F,
222 reload_observer: Option<&dyn ConfigReloadObserver>,
223 connection_observer: Option<&dyn ConfigSyncConnectionObserver>,
224 ) -> Result<()>
225 where
226 R: FnMut() -> RFut,
227 RFut: Future<Output = Result<()>>,
228 F: FnMut(ConfigReloadMessage) -> Fut,
229 Fut: Future<Output = Result<()>>,
230 {
231 let Some(notifier) = self.notifier().cloned() else {
232 shutdown.cancelled().await;
233 return Ok(());
234 };
235 run_config_reload_supervisor_with_observers(
236 notifier,
237 self.worker_config(),
238 shutdown,
239 reconcile,
240 reload,
241 reload_observer,
242 connection_observer,
243 )
244 .await
245 }
246}