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 pub fn namespace(&self) -> &str {
74 &self.namespace
75 }
76
77 pub fn runtime_id(&self) -> &str {
79 &self.runtime_id
80 }
81
82 pub fn notifier(&self) -> Option<&SharedConfigChangeNotifier> {
84 self.notifier.as_ref()
85 }
86
87 pub fn enabled(&self) -> bool {
89 self.notifier.is_some()
90 }
91
92 pub fn worker_config(&self) -> ConfigReloadWorkerConfig {
94 ConfigReloadWorkerConfig::new(self.namespace(), self.runtime_id())
95 }
96
97 pub async fn publish_reload(
99 &self,
100 keys: impl IntoIterator<Item = impl Into<String>>,
101 source: ConfigNotificationSource,
102 ) -> Result<()> {
103 let Some(notifier) = self.notifier() else {
104 return Ok(());
105 };
106
107 notifier
108 .publish_reload(ConfigReloadMessage::new(
109 self.namespace(),
110 self.runtime_id(),
111 keys,
112 source,
113 ))
114 .await
115 }
116
117 pub async fn run_reload_subscription<F, Fut>(
122 &self,
123 shutdown: CancellationToken,
124 reload: F,
125 ) -> Result<()>
126 where
127 F: FnMut(ConfigReloadMessage) -> Fut,
128 Fut: Future<Output = Result<()>>,
129 {
130 let Some(notifier) = self.notifier().cloned() else {
131 shutdown.cancelled().await;
132 return Ok(());
133 };
134 run_config_reload_worker(notifier, self.worker_config(), shutdown, reload).await
135 }
136
137 pub async fn run_reload_subscription_with_observer<F, Fut>(
139 &self,
140 shutdown: CancellationToken,
141 reload: F,
142 observer: Option<&dyn ConfigReloadObserver>,
143 ) -> Result<()>
144 where
145 F: FnMut(ConfigReloadMessage) -> Fut,
146 Fut: Future<Output = Result<()>>,
147 {
148 let Some(notifier) = self.notifier().cloned() else {
149 shutdown.cancelled().await;
150 return Ok(());
151 };
152 run_config_reload_worker_with_observer(
153 notifier,
154 self.worker_config(),
155 shutdown,
156 reload,
157 observer,
158 )
159 .await
160 }
161
162 pub async fn run_reload_subscription_with_reconcile<R, RFut, F, Fut>(
167 &self,
168 shutdown: CancellationToken,
169 reconcile: R,
170 reload: F,
171 ) -> Result<()>
172 where
173 R: FnMut() -> RFut,
174 RFut: Future<Output = Result<()>>,
175 F: FnMut(ConfigReloadMessage) -> Fut,
176 Fut: Future<Output = Result<()>>,
177 {
178 let Some(notifier) = self.notifier().cloned() else {
179 shutdown.cancelled().await;
180 return Ok(());
181 };
182 run_config_reload_supervisor(notifier, self.worker_config(), shutdown, reconcile, reload)
183 .await
184 }
185
186 pub async fn run_reload_subscription_with_reconcile_and_observers<R, RFut, F, Fut>(
188 &self,
189 shutdown: CancellationToken,
190 reconcile: R,
191 reload: F,
192 reload_observer: Option<&dyn ConfigReloadObserver>,
193 connection_observer: Option<&dyn ConfigSyncConnectionObserver>,
194 ) -> Result<()>
195 where
196 R: FnMut() -> RFut,
197 RFut: Future<Output = Result<()>>,
198 F: FnMut(ConfigReloadMessage) -> Fut,
199 Fut: Future<Output = Result<()>>,
200 {
201 let Some(notifier) = self.notifier().cloned() else {
202 shutdown.cancelled().await;
203 return Ok(());
204 };
205 run_config_reload_supervisor_with_observers(
206 notifier,
207 self.worker_config(),
208 shutdown,
209 reconcile,
210 reload,
211 reload_observer,
212 connection_observer,
213 )
214 .await
215 }
216}