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>(
135 &self,
136 shutdown: CancellationToken,
137 reload: F,
138 ) -> Result<()>
139 where
140 F: FnMut(ConfigReloadMessage) -> Fut,
141 Fut: Future<Output = Result<()>>,
142 {
143 let Some(notifier) = self.notifier().cloned() else {
144 shutdown.cancelled().await;
145 return Ok(());
146 };
147 run_config_reload_worker(notifier, self.worker_config(), shutdown, reload).await
148 }
149
150 pub async fn run_reload_subscription_with_observer<F, Fut>(
156 &self,
157 shutdown: CancellationToken,
158 reload: F,
159 observer: Option<&dyn ConfigReloadObserver>,
160 ) -> Result<()>
161 where
162 F: FnMut(ConfigReloadMessage) -> Fut,
163 Fut: Future<Output = Result<()>>,
164 {
165 let Some(notifier) = self.notifier().cloned() else {
166 shutdown.cancelled().await;
167 return Ok(());
168 };
169 run_config_reload_worker_with_observer(
170 notifier,
171 self.worker_config(),
172 shutdown,
173 reload,
174 observer,
175 )
176 .await
177 }
178
179 pub async fn run_reload_subscription_with_reconcile<R, RFut, F, Fut>(
188 &self,
189 shutdown: CancellationToken,
190 reconcile: R,
191 reload: F,
192 ) -> Result<()>
193 where
194 R: FnMut() -> RFut,
195 RFut: Future<Output = Result<()>>,
196 F: FnMut(ConfigReloadMessage) -> Fut,
197 Fut: Future<Output = Result<()>>,
198 {
199 let Some(notifier) = self.notifier().cloned() else {
200 shutdown.cancelled().await;
201 return Ok(());
202 };
203 run_config_reload_supervisor(notifier, self.worker_config(), shutdown, reconcile, reload)
204 .await
205 }
206
207 pub async fn run_reload_subscription_with_reconcile_and_observers<R, RFut, F, Fut>(
213 &self,
214 shutdown: CancellationToken,
215 reconcile: R,
216 reload: F,
217 reload_observer: Option<&dyn ConfigReloadObserver>,
218 connection_observer: Option<&dyn ConfigSyncConnectionObserver>,
219 ) -> Result<()>
220 where
221 R: FnMut() -> RFut,
222 RFut: Future<Output = Result<()>>,
223 F: FnMut(ConfigReloadMessage) -> Fut,
224 Fut: Future<Output = Result<()>>,
225 {
226 let Some(notifier) = self.notifier().cloned() else {
227 shutdown.cancelled().await;
228 return Ok(());
229 };
230 run_config_reload_supervisor_with_observers(
231 notifier,
232 self.worker_config(),
233 shutdown,
234 reconcile,
235 reload,
236 reload_observer,
237 connection_observer,
238 )
239 .await
240 }
241}