liminal_server/server/connection/
services_cluster.rs1use std::sync::{Arc, OnceLock};
11
12use liminal::channel::{ChannelRestartPolicy, ChannelSupervisor, ClusterObserver};
13use liminal::envelope::Envelope;
14
15use crate::ServerError;
16use crate::cluster::discovery::{ClusterResolver, as_resolver};
17use crate::config::types::ClusterConfig;
18
19#[derive(Clone, Debug)]
26pub struct ChannelCluster {
27 supervisor: ChannelSupervisor,
28 resolver: Option<Arc<ClusterResolver>>,
29 observer: Arc<ServerObserver>,
30}
31
32#[derive(Debug, Default)]
38pub struct ServerObserver {
39 cluster: OnceLock<Arc<dyn ClusterObserver>>,
40 console: OnceLock<Arc<crate::console::ConsoleHub>>,
41 #[cfg(test)]
44 witness: OnceLock<Arc<dyn ClusterObserver>>,
45 #[cfg(test)]
49 held_departures: std::sync::Mutex<Option<HeldDepartures>>,
50}
51
52#[cfg(test)]
55type HeldDepartures = (String, Vec<u64>);
56
57impl ServerObserver {
58 pub fn set_cluster(&self, cluster: Arc<dyn ClusterObserver>) -> Result<(), ServerError> {
61 self.cluster
62 .set(cluster)
63 .map_err(|_| ServerError::ClusterJoin {
64 message: "the channel observer already forwards to a cluster".to_owned(),
65 })
66 }
67
68 #[cfg(test)]
71 pub(crate) fn set_witness(&self, witness: Arc<dyn ClusterObserver>) -> Result<(), ServerError> {
72 self.witness
73 .set(witness)
74 .map_err(|_| ServerError::ClusterJoin {
75 message: "the channel observer already has a witness".to_owned(),
76 })
77 }
78
79 #[cfg(test)]
82 pub(crate) fn hold_departures(&self, channel: &str) -> std::io::Result<()> {
83 *self.held()? = Some((channel.to_owned(), Vec::new()));
84 Ok(())
85 }
86
87 #[cfg(test)]
89 pub(crate) fn release_departures(&self) -> std::io::Result<()> {
90 let held = self.held()?.take();
91 if let Some((channel, pids)) = held {
92 for pid in pids {
93 self.on_unsubscribe(&channel, pid);
94 }
95 }
96 Ok(())
97 }
98
99 #[cfg(test)]
102 fn held(&self) -> std::io::Result<std::sync::MutexGuard<'_, Option<HeldDepartures>>> {
103 self.held_departures.lock().map_err(|error| {
104 std::io::Error::other(format!("the held-departures lock was poisoned: {error}"))
105 })
106 }
107
108 #[cfg(test)]
111 fn held_back(&self, channel: &str, subscriber_pid: u64) -> bool {
112 let Ok(mut held) = self.held_departures.lock() else {
113 return false;
114 };
115 match held.as_mut() {
116 Some((held_channel, pids)) if held_channel == channel => {
117 pids.push(subscriber_pid);
118 true
119 }
120 _ => false,
121 }
122 }
123
124 pub fn set_console(&self, console: Arc<crate::console::ConsoleHub>) -> Result<(), ServerError> {
126 self.console
127 .set(console)
128 .map_err(|_| ServerError::ConfigValidation {
129 message: "the channel observer already feeds a console hub".to_owned(),
130 })
131 }
132}
133
134impl ServerObserver {
135 pub fn peer(&self, name: &str, present: bool) {
137 if let Some(console) = self.console.get()
138 && let Err(error) = console.emit(crate::console::TopologyChange::Peer {
139 name: name.to_owned(),
140 present,
141 })
142 {
143 tracing::warn!(%error, peer = name, "console topology change was not applied");
144 }
145 }
146}
147
148impl ClusterObserver for ServerObserver {
149 fn on_subscribe(&self, channel: &str, subscriber_pid: u64) {
150 if let Some(console) = self.console.get()
151 && let Err(error) = console.attach(channel)
152 {
153 tracing::warn!(%error, channel, "console tap did not attach");
154 }
155 #[cfg(test)]
156 if let Some(witness) = self.witness.get() {
157 witness.on_subscribe(channel, subscriber_pid);
158 }
159 if crate::console::tappable(channel)
162 && let Some(cluster) = self.cluster.get()
163 {
164 cluster.on_subscribe(channel, subscriber_pid);
165 }
166 }
167
168 fn on_unsubscribe(&self, channel: &str, subscriber_pid: u64) {
169 #[cfg(test)]
170 if self.held_back(channel, subscriber_pid) {
171 return;
172 }
173 if let Some(console) = self.console.get() {
174 if let Err(error) = console.detach(channel) {
175 tracing::warn!(%error, channel, "console tap did not detach");
176 }
177 if let Err(error) = console.tap().forget_receiver(subscriber_pid) {
178 console.observe_failed();
179 tracing::warn!(%error, channel, "TAP_RECEIVER_FAILED");
180 }
181 }
182 #[cfg(test)]
183 if let Some(witness) = self.witness.get() {
184 witness.on_unsubscribe(channel, subscriber_pid);
185 }
186 if crate::console::tappable(channel)
189 && let Some(cluster) = self.cluster.get()
190 {
191 cluster.on_unsubscribe(channel, subscriber_pid);
192 }
193 }
194
195 fn on_publish(&self, channel: &str, envelope: &Envelope) {
196 if !crate::console::tappable(channel) {
199 return;
200 }
201 if let Some(cluster) = self.cluster.get() {
202 cluster.on_publish(channel, envelope);
203 }
204 }
205}
206
207impl ChannelCluster {
208 #[must_use]
210 pub const fn observer(&self) -> &Arc<ServerObserver> {
211 &self.observer
212 }
213
214 #[must_use]
216 pub const fn supervisor(&self) -> &ChannelSupervisor {
217 &self.supervisor
218 }
219
220 #[must_use]
222 pub const fn resolver(&self) -> Option<&Arc<ClusterResolver>> {
223 self.resolver.as_ref()
224 }
225}
226
227fn server_channel_policy() -> ChannelRestartPolicy {
231 ChannelRestartPolicy::default()
232}
233
234pub fn build_channel_cluster(
244 cluster: Option<&ClusterConfig>,
245) -> Result<ChannelCluster, ServerError> {
246 let Some(cluster) = cluster else {
247 let supervisor =
248 ChannelSupervisor::with_policy(server_channel_policy()).map_err(|error| {
249 ServerError::ConfigValidation {
250 message: format!("failed to start channel supervisor: {error}"),
251 }
252 })?;
253 return Ok(with_observer(supervisor, None));
254 };
255 let resolver = Arc::new(ClusterResolver::new());
256 let supervisor = ChannelSupervisor::with_distribution(
257 cluster.node_name.clone(),
258 node_creation(),
259 cluster.cookie.clone(),
260 as_resolver(Arc::clone(&resolver)),
261 server_channel_policy(),
262 )
263 .map_err(|error| ServerError::ClusterJoin {
264 message: format!("failed to start clustered channel supervisor: {error}"),
265 })?;
266 Ok(with_observer(supervisor, Some(resolver)))
267}
268
269fn with_observer(
270 supervisor: ChannelSupervisor,
271 resolver: Option<Arc<ClusterResolver>>,
272) -> ChannelCluster {
273 let observer = Arc::new(ServerObserver::default());
274 supervisor.install_observer(Arc::clone(&observer) as Arc<dyn ClusterObserver>);
275 ChannelCluster {
276 supervisor,
277 resolver,
278 observer,
279 }
280}
281
282fn node_creation() -> u32 {
292 let since_epoch = std::time::SystemTime::now()
297 .duration_since(std::time::UNIX_EPOCH)
298 .map_or(0, |duration| duration.as_secs());
299 let folded = u32::try_from(since_epoch & u64::from(u32::MAX)).unwrap_or(u32::MAX);
303 (folded & 0x7fff_ffff).max(1)
304}