Mountain/RunTime/Shutdown/
Shutdown.rs1use std::sync::Arc;
49
50use CommonLibrary::{
51 Environment::Requires::Requires,
52 Error::CommonError::CommonError,
53 IPC::IPCProvider::IPCProvider,
54 Terminal::TerminalProvider::TerminalProvider as TerminalProviderTrait,
55};
56
57use crate::{RunTime::ApplicationRunTime::ApplicationRunTime, dev_log};
58
59impl ApplicationRunTime {
60 pub async fn Shutdown(&self) {
62 dev_log!("lifecycle", "[ApplicationRunTime] Initiating graceful shutdown of services...");
63
64 let shutdown_result = self.ShutdownWithRecovery().await;
65
66 match shutdown_result {
67 Ok(()) => {
68 dev_log!(
69 "lifecycle",
70 "[ApplicationRunTime] Service shutdown tasks completed successfully."
71 )
72 },
73 Err(error) => {
74 dev_log!(
75 "lifecycle",
76 "error: [ApplicationRunTime] Service shutdown completed with errors: {}",
77 error
78 )
79 },
80 }
81 }
82
83 pub async fn ShutdownWithRecovery(&self) -> Result<(), CommonError> {
85 dev_log!("lifecycle", "[ApplicationRunTime] Initiating robust shutdown with recovery...");
86
87 let mut shutdown_errors:Vec<String> = Vec::new();
88
89 match self.ShutdownCocoonWithRetry().await {
91 Ok(()) => dev_log!("lifecycle", "[ApplicationRunTime] Cocoon shutdown successful"),
92 Err(error) => {
93 shutdown_errors.push(format!("Cocoon shutdown failed: {}", error));
94 dev_log!(
95 "lifecycle",
96 "warn: [ApplicationRunTime] Cocoon shutdown failed, continuing with other services..."
97 );
98 },
99 }
100
101 match self.DisposeTerminalsSafely().await {
103 Ok(()) => dev_log!("lifecycle", "[ApplicationRunTime] Terminal disposal successful"),
104 Err(error) => {
105 shutdown_errors.push(format!("Terminal disposal failed: {}", error));
106 dev_log!(
107 "lifecycle",
108 "warn: [ApplicationRunTime] Terminal disposal failed, continuing..."
109 );
110 },
111 }
112
113 match self.SaveApplicationState().await {
115 Ok(()) => dev_log!("lifecycle", "[ApplicationRunTime] Application state saved"),
116 Err(error) => {
117 shutdown_errors.push(format!("State save failed: {}", error));
118 dev_log!(
119 "lifecycle",
120 "warn: [ApplicationRunTime] Failed to save application state, continuing..."
121 );
122 },
123 }
124
125 self.FlushPendingOperations().await;
127
128 if !shutdown_errors.is_empty() {
129 Err(CommonError::Unknown {
130 Description:format!(
131 "Shutdown completed with {} errors: {:?}",
132 shutdown_errors.len(),
133 shutdown_errors
134 ),
135 })
136 } else {
137 Ok(())
138 }
139 }
140
141 pub async fn ShutdownCocoonWithRetry(&self) -> Result<(), CommonError> {
143 let IPCProvider:Arc<dyn IPCProvider> = self.Environment.Require();
144
145 let mut attempts = 0;
146 let max_attempts = 3;
147
148 while attempts < max_attempts {
149 match IPCProvider
150 .SendNotificationToSideCar("cocoon-main".to_string(), "$shutdown".to_string(), serde_json::Value::Null)
151 .await
152 {
153 Ok(()) => {
154 tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
156 return Ok(());
157 },
158 Err(error) => {
159 attempts += 1;
160 if attempts == max_attempts {
161 return Err(error);
162 }
163
164 dev_log!(
165 "lifecycle",
166 "warn: [ApplicationRunTime] Cocoon shutdown attempt {} failed: {}. Retrying...",
167 attempts,
168 error
169 );
170
171 tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
172 },
173 }
174 }
175
176 Err(CommonError::Unknown { Description:"Failed to shutdown Cocoon after maximum retries".to_string() })
177 }
178
179 pub async fn DisposeTerminalsSafely(&self) -> Result<(), CommonError> {
181 let TerminalProvider:Arc<dyn TerminalProviderTrait> = self.Environment.Require();
182
183 let TerminalIds:Vec<u64> = {
184 let TerminalsGuard = self
185 .Environment
186 .ApplicationState
187 .Feature
188 .Terminals
189 .ActiveTerminals
190 .lock()
191 .map_err(|e| CommonError::StateLockPoisoned { Context:e.to_string() })?;
192
193 TerminalsGuard.keys().cloned().collect()
194 };
195
196 let mut disposal_errors:Vec<String> = Vec::new();
197
198 for id in TerminalIds {
199 match TerminalProvider.DisposeTerminal(id).await {
200 Ok(()) => dev_log!("lifecycle", "[ApplicationRunTime] Terminal {} disposed successfully", id),
201 Err(error) => {
202 disposal_errors.push(format!("Terminal {}: {}", id, error));
203 dev_log!(
204 "lifecycle",
205 "warn: [ApplicationRunTime] Failed to dispose terminal {}: {}",
206 id,
207 error
208 );
209 },
210 }
211 }
212
213 if !disposal_errors.is_empty() {
214 Err(CommonError::Unknown {
215 Description:format!(
216 "Terminal disposal completed with {} errors: {:?}",
217 disposal_errors.len(),
218 disposal_errors
219 ),
220 })
221 } else {
222 Ok(())
223 }
224 }
225
226 pub async fn SaveApplicationState(&self) -> Result<(), CommonError> {
228 dev_log!("lifecycle", "[ApplicationRunTime] Saving application state...");
229
230 let global_memento_guard = self
232 .Environment
233 .ApplicationState
234 .Configuration
235 .MementoGlobalStorage
236 .lock()
237 .map_err(|e| CommonError::StateLockPoisoned { Context:e.to_string() })?;
238
239 let global_memento_path = self
240 .Environment
241 .ApplicationState
242 .GlobalMementoPath
243 .lock()
244 .map_err(|e| CommonError::StateLockPoisoned { Context:e.to_string() })?
245 .clone();
246
247 if let Some(parent) = global_memento_path.parent() {
248 if !parent.exists() {
249 std::fs::create_dir_all(parent)
250 .map_err(|e| CommonError::FileSystemIO { Path:parent.to_path_buf(), Description:e.to_string() })?;
251 }
252 }
253
254 let memento_json = serde_json::to_string_pretty(&*global_memento_guard)
255 .map_err(|e| CommonError::SerializationError { Description:e.to_string() })?;
256
257 std::fs::write(&global_memento_path, memento_json)
258 .map_err(|e| CommonError::FileSystemIO { Path:global_memento_path.clone(), Description:e.to_string() })
259 }
260
261 pub async fn FlushPendingOperations(&self) {
263 dev_log!("lifecycle", "[ApplicationRunTime] Flushing pending operations...");
264
265 let mut pending_requests_guard = self
267 .Environment
268 .ApplicationState
269 .UI
270 .PendingUserInterfaceRequest
271 .lock()
272 .unwrap_or_else(|e| {
273 dev_log!(
274 "lifecycle",
275 "error: [ApplicationRunTime] Failed to lock pending UI requests: {}",
276 e
277 );
278 e.into_inner()
279 });
280
281 for (_request_id, sender) in pending_requests_guard.drain() {
282 let _ = sender.send(Err(CommonError::Unknown {
283 Description:"Application shutting down".to_string(),
284 }));
285 }
286
287 dev_log!("lifecycle", "[ApplicationRunTime] Pending operations flushed");
288 }
289}