liminal_server/server/connection/
supervisor_lifecycle.rs1use std::sync::{Arc, Mutex};
2use std::thread::JoinHandle;
3
4use super::super::reclaim_placement::ReclaimRelease;
5use super::{ConnectionIncarnationAuthority, ConnectionSupervisor, SupervisorInner};
6use crate::ServerError;
7
8#[derive(Debug, Default)]
9pub(super) struct BackgroundStart {
10 started: bool,
11 stopped: bool,
12 worker: Option<JoinHandle<()>>,
13 incarnation: Option<JoinHandle<()>>,
15 failure: Option<String>,
16 reclaim_releases: Vec<ReclaimRelease>,
17}
18
19impl ConnectionSupervisor {
20 pub(crate) fn retain_reclaim_release(
21 &self,
22 release: ReclaimRelease,
23 ) -> Result<(), ServerError> {
24 let mut start = self
25 .inner
26 .background
27 .lock()
28 .map_err(|_| refusal("connection background start lock poisoned"))?;
29 if start.stopped {
30 return Err(refusal("spine release cannot be registered after shutdown"));
31 }
32 start.reclaim_releases.push(release);
33 drop(start);
34 Ok(())
35 }
36
37 pub(crate) fn listening(&self) -> Result<(), ServerError> {
38 let mut start = self
39 .inner
40 .background
41 .lock()
42 .map_err(|_| refusal("connection background start lock poisoned"))?;
43 if start.stopped {
44 return Err(refusal(
45 "connection background work cannot start after shutdown",
46 ));
47 }
48 if !start.started {
49 start.worker = self.inner.runtime.services_arc().listening();
50 start.incarnation = self.start_incarnation()?;
51 start.started = true;
52 }
53 drop(start);
54 Ok(())
55 }
56
57 fn start_incarnation(&self) -> Result<Option<JoinHandle<()>>, ServerError> {
68 let Some(authority) = self.inner.incarnations.clone() else {
69 return Ok(None);
70 };
71 let fatal = self.inner.runtime.fatal_shutdown.clone();
72 let held = Arc::clone(&self.inner.held);
73 let supervisor = Arc::downgrade(&self.inner);
74 held.starting();
75 std::thread::Builder::new()
76 .name("liminal-incarnation-start".to_owned())
77 .spawn(move || {
78 let started = authority.ensure_started();
79 if held.admitting() {
80 held.admit_held(|admit| {
86 let supervisor = supervisor.upgrade().map(|inner| Self { inner });
87 if let Some(supervisor) = &supervisor {
88 admit(supervisor);
89 }
90 supervisor
91 });
92 }
93 let settled = started.and_then(|()| authority.settle_anchor());
97 if let Err(error) = settled
98 && !ConnectionIncarnationAuthority::is_abandoned(&error)
99 {
100 tracing::error!(%error, "the incarnation start or its anchor swap failed behind the bound listener; the server stops");
101 if let Some(fatal) = fatal {
102 fatal.initiate();
103 }
104 }
105 })
106 .map(Some)
107 .map_err(|error| {
108 self.inner.held.stop();
109 refusal(format!("the incarnation start could not begin: {error}"))
110 })
111 }
112
113 pub(in crate::server) fn admit_when_started(&self, admit: impl FnOnce(&Self) + Send + 'static) {
118 if let Some(admit) = self.inner.held.hold(Box::new(admit)) {
119 admit(self);
120 }
121 }
122
123 #[must_use]
126 pub fn incarnation_start_failure(&self) -> Option<ServerError> {
127 self.inner
128 .incarnations
129 .as_ref()
130 .and_then(|authority| authority.start_failure())
131 }
132
133 pub(in crate::server) fn finish_store_work(&self) -> Result<(), ServerError> {
134 self.inner.finish_store_work()
135 }
136
137 pub(in crate::server) fn release_store_holders(&self) -> Result<(), ServerError> {
138 self.inner.runtime.services().release_store_holders()
139 }
140}
141
142impl SupervisorInner {
143 fn finish_store_work(&self) -> Result<(), ServerError> {
144 #[cfg(test)]
145 let observer = self
146 .reclaim_stop_observer
147 .lock()
148 .map_err(|_| refusal("reclamation stop observer lock poisoned"))?
149 .take();
150 #[cfg(test)]
151 if let Some(observer) = observer {
152 observer
153 .send(true)
154 .map_err(|error| refusal(error.to_string()))?;
155 }
156 self.held.stop();
157 if let Some(authority) = &self.incarnations {
158 authority.abandon();
159 }
160 first_failure([
161 self.reclaim.finish(&self.scheduler),
162 join_background(&self.background),
163 self.runtime.services().finish_background_store_work(),
164 ])
165 }
166}
167
168impl Drop for SupervisorInner {
169 fn drop(&mut self) {
170 crate::server::boot_steps::stop_timed("connection_drop_scheduler", || {
173 self.scheduler.shutdown();
174 });
175 let finished =
176 crate::server::boot_steps::stop_timed("connection_drop_store_finish", || {
177 self.finish_store_work()
178 });
179 if let Err(error) = finished {
180 tracing::error!(%error, "connection supervisor store teardown failed");
181 }
182 }
183}
184
185fn join_background(background: &Mutex<BackgroundStart>) -> Result<(), ServerError> {
186 let mut start = background
187 .lock()
188 .map_err(|_| refusal("connection background join lock poisoned"))?;
189 start.stopped = true;
190 if let Some(failure) = &start.failure {
191 return Err(refusal(failure.clone()));
192 }
193 let joined = start.worker.take().map_or(Ok(()), |worker| {
194 worker
195 .join()
196 .map_err(|_| refusal("connection background store work panicked during shutdown"))
197 });
198 let started = start.incarnation.take().map_or(Ok(()), |worker| {
199 if worker.thread().id() == std::thread::current().id() {
203 return Ok(());
204 }
205 crate::server::boot_steps::stop_timed("incarnation_join", || worker.join())
206 .map_err(|_| refusal("the incarnation start panicked during shutdown"))
207 });
208 let mut results = vec![joined, started];
209 for release in &mut start.reclaim_releases {
210 results.push(release.finish());
211 }
212 start.reclaim_releases.clear();
213 let mut first = None;
214 for result in results {
215 if let Err(error) = result {
216 tracing::error!(%error, "background store teardown failed");
217 if first.is_none() {
218 first = Some(error);
219 }
220 }
221 }
222 if let Some(error) = first {
223 start.failure = Some(error.to_string());
224 return Err(error);
225 }
226 drop(start);
227 Ok(())
228}
229
230fn first_failure<const N: usize>(results: [Result<(), ServerError>; N]) -> Result<(), ServerError> {
231 let mut first = None;
232 for result in results {
233 if let Err(error) = result {
234 tracing::error!(%error, "connection store work teardown failed");
235 if first.is_none() {
236 first = Some(error);
237 }
238 }
239 }
240 first.map_or(Ok(()), Err)
241}
242
243fn refusal(message: impl Into<String>) -> ServerError {
244 ServerError::ListenerAccept {
245 message: message.into(),
246 }
247}