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