1use std::{collections::HashMap, sync::Arc};
91
92use serde::{Deserialize, Serialize};
93use tokio::sync::RwLock;
94
95use crate::{AirError, Result, Utility, dev_log};
96
97#[derive(Debug)]
99pub struct HealthCheckManager {
100 ServiceHealth:Arc<RwLock<HashMap<String, ServiceHealth>>>,
102
103 HealthHistory:Arc<RwLock<Vec<HealthCheckRecord>>>,
105
106 RecoveryActions:Arc<RwLock<HashMap<String, RecoveryAction>>>,
108
109 config:HealthCheckConfig,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct ServiceHealth {
116 pub ServiceName:String,
118
119 pub Status:HealthStatus,
121
122 pub LastCheck:u64,
124
125 pub LastSuccess:Option<u64>,
127
128 pub FailureCount:u32,
130
131 pub ErrorMessage:Option<String>,
133
134 pub ResponseTimeMs:Option<u64>,
136
137 pub CheckLevel:HealthCheckLevel,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
143pub enum HealthStatus {
144 Healthy,
146
147 Degraded,
149
150 Unhealthy,
152
153 Unknown,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
159pub enum HealthCheckLevel {
160 Alive,
162
163 Responsive,
165
166 Functional,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct HealthCheckRecord {
173 pub Timestamp:u64,
175
176 pub ServiceName:String,
178
179 pub Status:HealthStatus,
181
182 pub ResponseTimeMs:Option<u64>,
184
185 pub ErrorMessage:Option<String>,
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize)]
191pub struct RecoveryAction {
192 pub Name:String,
194
195 pub ServiceName:String,
197
198 pub Trigger:RecoveryTrigger,
200
201 pub Action:RecoveryActionType,
203
204 pub MaxRetries:u32,
206
207 pub RetryCount:u32,
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize)]
213pub enum RecoveryTrigger {
214 ConsecutiveFailures(u32),
216
217 ResponseTimeExceeds(u64),
219
220 ServiceUnresponsive,
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
226pub enum RecoveryActionType {
227 RestartService,
229
230 ResetConnection,
232
233 ClearCache,
235
236 ReloadConfiguration,
238
239 Escalate,
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize)]
245pub struct HealthCheckConfig {
246 pub DefaultCheckInterval:u64,
248
249 pub HistoryRetention:usize,
251
252 pub ConsecutiveFailuresThreshold:u32,
254
255 pub ResponseTimeThresholdMs:u64,
257
258 pub EnableAutoRecovery:bool,
260
261 pub RecoveryTimeoutSec:u64,
263}
264
265impl Default for HealthCheckConfig {
266 fn default() -> Self {
267 Self {
268 DefaultCheckInterval:30,
269
270 HistoryRetention:100,
271
272 ConsecutiveFailuresThreshold:3,
273
274 ResponseTimeThresholdMs:5000,
275
276 EnableAutoRecovery:true,
277
278 RecoveryTimeoutSec:60,
279 }
280 }
281}
282
283impl HealthCheckManager {
284 pub fn new(config:Option<HealthCheckConfig>) -> Self {
286 Self {
287 ServiceHealth:Arc::new(RwLock::new(HashMap::new())),
288
289 HealthHistory:Arc::new(RwLock::new(Vec::new())),
290
291 RecoveryActions:Arc::new(RwLock::new(HashMap::new())),
292
293 config:config.unwrap_or_default(),
294 }
295 }
296
297 pub async fn RegisterService(&self, ServiceName:String, CheckLevel:HealthCheckLevel) -> Result<()> {
299 let mut HealthMap = self.ServiceHealth.write().await;
300
301 HealthMap.insert(
302 ServiceName.clone(),
303 ServiceHealth {
304 ServiceName:ServiceName.clone(),
305 Status:HealthStatus::Unknown,
306 LastCheck:0,
307 LastSuccess:None,
308 FailureCount:0,
309 ErrorMessage:None,
310 ResponseTimeMs:None,
311 CheckLevel:CheckLevel.clone(),
312 },
313 );
314
315 dev_log!(
316 "lifecycle",
317 "[HealthCheck] Registered service for monitoring: {} ({:?})",
318 ServiceName,
319 CheckLevel
320 );
321
322 Ok(())
323 }
324
325 pub async fn CheckService(&self, ServiceName:&str) -> Result<HealthStatus> {
327 let StartTime = Utility::CurrentTimestamp();
328
329 let CheckTimeout = tokio::time::Duration::from_secs(10);
331
332 let (status, ErrorMessage) = tokio::time::timeout(CheckTimeout, async {
333 match ServiceName {
334 "authentication" => self.CheckAuthenticationService().await,
335 "updates" => self.CheckUpdatesService().await,
336 "downloader" => self.CheckDownloaderService().await,
337 "indexing" => self.CheckIndexingService().await,
338 "grpc" => self.CheckgRPCService().await,
339 "connections" => self.CheckConnectionsService().await,
340 _ => {
341 dev_log!("lifecycle", "warn: [HealthCheck] Unknown service: {}", ServiceName);
342 return (HealthStatus::Unhealthy, Some(format!("Unknown service: {}", ServiceName)));
343 },
344 }
345 })
346 .await
347 .map_err(|_| {
348 dev_log!("lifecycle", "warn: [HealthCheck] Timeout checking service: {}", ServiceName);
349 (
350 HealthStatus::Unhealthy,
351 Some(format!("Health check timeout for service: {}", ServiceName)),
352 )
353 })?;
354
355 let ResponseTime = Utility::CurrentTimestamp() - StartTime;
356
357 self.UpdateServiceHealth(ServiceName, status.clone(), &ErrorMessage, ResponseTime)
359 .await?;
360
361 self.RecordHealthCheck(ServiceName, status.clone(), ResponseTime, &ErrorMessage)
363 .await;
364
365 if self.config.EnableAutoRecovery {
367 self.TriggerRecoveryIfNeeded(ServiceName).await;
368 }
369
370 self.HandleCriticalAlerts(ServiceName, &status).await;
372
373 Ok(status)
374 }
375
376 async fn CheckAuthenticationService(&self) -> (HealthStatus, Option<String>) {
378 dev_log!("lifecycle", "[HealthCheck] Checking authentication service health");
379
380 let start = std::time::Instant::now();
385
386 tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
396
397 let elapsed = start.elapsed();
398
399 if elapsed.as_millis() > 1000 {
401 return (
402 HealthStatus::Degraded,
403 Some(format!(
404 "Authentication service response time too slow: {}ms",
405 elapsed.as_millis()
406 )),
407 );
408 }
409
410 dev_log!("lifecycle", "[HealthCheck] Authentication service healthy");
411
412 (HealthStatus::Healthy, None)
413 }
414
415 async fn CheckUpdatesService(&self) -> (HealthStatus, Option<String>) {
417 dev_log!("lifecycle", "[HealthCheck] Checking updates service health");
418
419 let start = std::time::Instant::now();
420
421 tokio::time::sleep(tokio::time::Duration::from_millis(30)).await;
431
432 let elapsed = start.elapsed();
433
434 if elapsed.as_millis() > 500 {
436 return (
437 HealthStatus::Degraded,
438 Some(format!("Updates service response time too slow: {}ms", elapsed.as_millis())),
439 );
440 }
441
442 dev_log!("lifecycle", "[HealthCheck] Updates service healthy");
443
444 (HealthStatus::Healthy, None)
445 }
446
447 async fn CheckDownloaderService(&self) -> (HealthStatus, Option<String>) {
449 dev_log!("lifecycle", "[HealthCheck] Checking downloader service health");
450
451 let start = std::time::Instant::now();
452
453 tokio::time::sleep(tokio::time::Duration::from_millis(40)).await;
464
465 let elapsed = start.elapsed();
466
467 if elapsed.as_millis() > 1000 {
469 return (
470 HealthStatus::Degraded,
471 Some(format!("Downloader service response time too slow: {}ms", elapsed.as_millis())),
472 );
473 }
474
475 dev_log!("lifecycle", "[HealthCheck] Downloader service healthy");
476
477 (HealthStatus::Healthy, None)
478 }
479
480 async fn CheckIndexingService(&self) -> (HealthStatus, Option<String>) {
482 dev_log!("lifecycle", "[HealthCheck] Checking indexing service health");
483
484 let start = std::time::Instant::now();
485
486 tokio::time::sleep(tokio::time::Duration::from_millis(60)).await;
497
498 let elapsed = start.elapsed();
499
500 if elapsed.as_millis() > 500 {
502 return (
503 HealthStatus::Degraded,
504 Some(format!("Indexing service response time too slow: {}ms", elapsed.as_millis())),
505 );
506 }
507
508 dev_log!("lifecycle", "[HealthCheck] Indexing service healthy");
509
510 (HealthStatus::Healthy, None)
511 }
512
513 async fn CheckgRPCService(&self) -> (HealthStatus, Option<String>) {
515 dev_log!("lifecycle", "[HealthCheck] Checking gRPC service health");
516
517 let start = std::time::Instant::now();
518
519 tokio::time::sleep(tokio::time::Duration::from_millis(20)).await;
530
531 let elapsed = start.elapsed();
532
533 if elapsed.as_millis() > 200 {
535 return (
536 HealthStatus::Degraded,
537 Some(format!("gRPC service response time too slow: {}ms", elapsed.as_millis())),
538 );
539 }
540
541 dev_log!("lifecycle", "[HealthCheck] gRPC service healthy");
542
543 (HealthStatus::Healthy, None)
544 }
545
546 async fn CheckConnectionsService(&self) -> (HealthStatus, Option<String>) {
548 dev_log!("lifecycle", "[HealthCheck] Checking connections service health");
549
550 let start = std::time::Instant::now();
551
552 tokio::time::sleep(tokio::time::Duration::from_millis(35)).await;
563
564 let elapsed = start.elapsed();
565
566 if elapsed.as_millis() > 300 {
568 return (
569 HealthStatus::Degraded,
570 Some(format!("Connections service response time too slow: {}ms", elapsed.as_millis())),
571 );
572 }
573
574 dev_log!("lifecycle", "[HealthCheck] Connections service healthy");
575
576 (HealthStatus::Healthy, None)
577 }
578
579 async fn UpdateServiceHealth(
581 &self,
582
583 ServiceName:&str,
584
585 status:HealthStatus,
586
587 ErrorMessage:&Option<String>,
588
589 ResponseTime:u64,
590 ) -> Result<()> {
591 let mut HealthMap = self.ServiceHealth.write().await;
592
593 if let Some(ServiceHealth) = HealthMap.get_mut(ServiceName) {
594 ServiceHealth.Status = status.clone();
595
596 ServiceHealth.LastCheck = Utility::CurrentTimestamp();
597
598 ServiceHealth.ResponseTimeMs = Some(ResponseTime);
599
600 match status {
601 HealthStatus::Healthy => {
602 ServiceHealth.LastSuccess = Some(Utility::CurrentTimestamp());
603
604 ServiceHealth.FailureCount = 0;
605
606 ServiceHealth.ErrorMessage = None;
607 },
608
609 HealthStatus::Degraded | HealthStatus::Unhealthy => {
610 ServiceHealth.FailureCount += 1;
611
612 ServiceHealth.ErrorMessage = ErrorMessage.clone();
613 },
614
615 HealthStatus::Unknown => {
616
617 },
619 }
620 } else {
621 return Err(AirError::Internal(format!("Service not registered: {}", ServiceName)));
622 }
623
624 dev_log!(
625 "lifecycle",
626 "[HealthCheck] Updated health for {}: {:?} ({}ms)",
627 ServiceName,
628 status,
629 ResponseTime
630 );
631
632 Ok(())
633 }
634
635 async fn RecordHealthCheck(
637 &self,
638
639 ServiceName:&str,
640
641 status:HealthStatus,
642
643 ResponseTime:u64,
644
645 ErrorMessage:&Option<String>,
646 ) {
647 let mut history = self.HealthHistory.write().await;
648
649 let record = HealthCheckRecord {
650 Timestamp:Utility::CurrentTimestamp(),
651
652 ServiceName:ServiceName.to_string(),
653
654 Status:status,
655
656 ResponseTimeMs:Some(ResponseTime),
657
658 ErrorMessage:ErrorMessage.clone(),
659 };
660
661 history.push(record);
662
663 if history.len() > self.config.HistoryRetention {
665 history.remove(0);
666 }
667 }
668
669 async fn TriggerRecoveryIfNeeded(&self, ServiceName:&str) {
671 let HealthMap = self.ServiceHealth.read().await;
672
673 if let Some(ServiceHealth) = HealthMap.get(ServiceName) {
674 if ServiceHealth.FailureCount >= self.config.ConsecutiveFailuresThreshold {
676 dev_log!(
677 "lifecycle",
678 "warn: [HealthCheck] Service {} has {} consecutive failures, triggering recovery",
679 ServiceName,
680 ServiceHealth.FailureCount
681 );
682
683 self.PerformRecoveryAction(ServiceName).await;
684 }
685
686 if let Some(ResponseTime) = ServiceHealth.ResponseTimeMs {
688 if ResponseTime > self.config.ResponseTimeThresholdMs {
689 dev_log!(
690 "lifecycle",
691 "warn: [HealthCheck] Service {} response time {}ms exceeds threshold {}ms",
692 ServiceName,
693 ResponseTime,
694 self.config.ResponseTimeThresholdMs
695 );
696
697 self.HandleResponseTimeRecovery(ServiceName, ResponseTime).await;
698 }
699 }
700 }
701 }
702
703 async fn HandleResponseTimeRecovery(&self, ServiceName:&str, ResponseTime:u64) {
705 dev_log!(
706 "lifecycle",
707 "[HealthCheck] Handling response time recovery for {}: {}ms",
708 ServiceName,
709 ResponseTime
710 );
711
712 match ServiceName {
713 "grpc" => {
714 dev_log!(
715 "lifecycle",
716 "warn: [HealthCheck] Response time recovery: Optimizing gRPC server for {}",
717 ServiceName
718 );
719
720 },
725
726 "connections" => {
727 dev_log!(
728 "lifecycle",
729 "warn: [HealthCheck] Response time recovery: Optimizing connections for {}",
730 ServiceName
731 );
732
733 },
738
739 _ => {
740 dev_log!(
741 "lifecycle",
742 "warn: [HealthCheck] Response time recovery: Generic optimization for {}",
743 ServiceName
744 );
745 },
746 }
747 }
748
749 async fn HandleCriticalAlerts(&self, ServiceName:&str, status:&HealthStatus) {
751 if *status == HealthStatus::Unhealthy {
752 dev_log!(
753 "lifecycle",
754 "warn: [HealthCheck] CRITICAL: Service {} is UNHEALTHY - immediate attention required",
755 ServiceName
756 );
757
758 }
764 }
765
766 async fn PerformRecoveryAction(&self, ServiceName:&str) {
768 dev_log!("lifecycle", "[HealthCheck] Performing recovery action for {}", ServiceName);
769
770 let RecoveryTimeout = tokio::time::Duration::from_secs(self.config.RecoveryTimeoutSec);
771
772 let result = tokio::time::timeout(RecoveryTimeout, async {
773 match ServiceName {
774 "authentication" => self.RestartAuthenticationService().await,
775 "updates" => self.RestartUpdatesService().await,
776 "downloader" => self.RestartDownloaderService().await,
777 "indexing" => self.RestartIndexingService().await,
778 "grpc" => self.RestartgRPCService().await,
779 "connections" => self.ResetConnectionsService().await,
780 _ => {
781 dev_log!(
782 "lifecycle",
783 "warn: [HealthCheck] No specific recovery action for {}",
784 ServiceName
785 );
786 Ok(())
787 },
788 }
789 })
790 .await;
791
792 match result {
793 Ok(Ok(())) => {
794 dev_log!(
795 "lifecycle",
796 "[HealthCheck] Recovery action completed successfully for {}",
797 ServiceName
798 );
799 },
800
801 Ok(Err(e)) => {
802 dev_log!(
803 "lifecycle",
804 "warn: [HealthCheck] Recovery action failed for {}: {:?}",
805 ServiceName,
806 e
807 );
808 },
809
810 Err(_) => {
811 dev_log!("lifecycle", "warn: [HealthCheck] Recovery action timed out for {}", ServiceName);
812 },
813 }
814 }
815
816 async fn RestartAuthenticationService(&self) -> Result<()> {
818 dev_log!("lifecycle", "warn: [HealthCheck] Recovery: Restarting authentication service"); Ok(())
820 }
821
822 async fn RestartUpdatesService(&self) -> Result<()> {
824 dev_log!("lifecycle", "warn: [HealthCheck] Recovery: Restarting updates service"); Ok(())
826 }
827
828 async fn RestartDownloaderService(&self) -> Result<()> {
830 dev_log!("lifecycle", "warn: [HealthCheck] Recovery: Restarting downloader service"); Ok(())
832 }
833
834 async fn RestartIndexingService(&self) -> Result<()> {
836 dev_log!("lifecycle", "warn: [HealthCheck] Recovery: Restarting indexing service"); Ok(())
838 }
839
840 async fn RestartgRPCService(&self) -> Result<()> {
842 dev_log!("lifecycle", "warn: [HealthCheck] Recovery: Restarting gRPC server"); Ok(())
844 }
845
846 async fn ResetConnectionsService(&self) -> Result<()> {
848 dev_log!("lifecycle", "warn: [HealthCheck] Recovery: Resetting connections service"); Ok(())
850 }
851
852 pub async fn GetOverallHealth(&self) -> HealthStatus {
854 let HealthMap = self.ServiceHealth.read().await;
855
856 let mut HealthyCount = 0;
857
858 let mut DegradedCount = 0;
859
860 let mut UnhealthyCount = 0;
861
862 for ServiceHealth in HealthMap.values() {
863 match ServiceHealth.Status {
864 HealthStatus::Healthy => HealthyCount += 1,
865
866 HealthStatus::Degraded => DegradedCount += 1,
867
868 HealthStatus::Unhealthy => UnhealthyCount += 1,
869
870 HealthStatus::Unknown => {},
871 }
872 }
873
874 if UnhealthyCount > 0 {
875 HealthStatus::Unhealthy
876 } else if DegradedCount > 0 {
877 HealthStatus::Degraded
878 } else if HealthyCount > 0 {
879 HealthStatus::Healthy
880 } else {
881 HealthStatus::Unknown
882 }
883 }
884
885 pub async fn GetServiceHealth(&self, service_name:&str) -> Option<ServiceHealth> {
887 let HealthMap = self.ServiceHealth.read().await;
888
889 HealthMap.get(service_name).cloned()
890 }
891
892 pub async fn GetHealthHistory(&self, service_name:Option<&str>, limit:Option<usize>) -> Vec<HealthCheckRecord> {
894 let History = self.HealthHistory.read().await;
895
896 let mut FilteredHistory:Vec<HealthCheckRecord> = if let Some(service) = service_name {
897 History.iter().filter(|Record| Record.ServiceName == service).cloned().collect()
898 } else {
899 History.clone()
900 };
901
902 FilteredHistory.reverse();
904
905 if let Some(limit) = limit {
907 FilteredHistory.truncate(limit);
908 }
909
910 FilteredHistory
911 }
912
913 pub async fn RegisterRecoveryAction(&self, action:RecoveryAction) -> Result<()> {
915 let mut actions = self.RecoveryActions.write().await;
916
917 actions.insert(action.Name.clone(), action);
918
919 Ok(())
920 }
921
922 pub async fn GetHealthStatistics(&self) -> HealthStatistics {
924 let HealthMap = self.ServiceHealth.read().await;
925
926 let history = self.HealthHistory.read().await;
927
928 let mut HealthyServices = 0;
930
931 let mut DegradedServices = 0;
932
933 let mut UnhealthyServices = 0;
934
935 for ServiceHealth in HealthMap.values() {
936 match ServiceHealth.Status {
937 HealthStatus::Healthy => HealthyServices += 1,
938
939 HealthStatus::Degraded => DegradedServices += 1,
940
941 HealthStatus::Unhealthy => UnhealthyServices += 1,
942
943 HealthStatus::Unknown => {},
944 }
945 }
946
947 let mut Statistics = HealthStatistics {
949 TotalServices:HealthMap.len(),
950
951 HealthyServices,
952
953 DegradedServices,
954
955 UnhealthyServices,
956
957 TotalChecks:history.len(),
958
959 AverageResponseTimeMs:0.0,
960
961 SuccessRate:0.0,
962 };
963
964 if !history.is_empty() {
966 let mut TotalResponseTime = 0;
967
968 let mut SuccessfulChecks = 0;
969
970 for Record in history.iter() {
971 if let Some(ResponseTime) = Record.ResponseTimeMs {
972 TotalResponseTime += ResponseTime;
973 }
974
975 if Record.Status == HealthStatus::Healthy {
976 SuccessfulChecks += 1;
977 }
978 }
979
980 Statistics.AverageResponseTimeMs = TotalResponseTime as f64 / history.len() as f64;
981
982 Statistics.SuccessRate = SuccessfulChecks as f64 / history.len() as f64 * 100.0;
983 }
984
985 Statistics
986 }
987}
988
989#[derive(Debug, Clone, Serialize, Deserialize)]
991pub struct HealthStatistics {
992 pub TotalServices:usize,
993
994 pub HealthyServices:usize,
995
996 pub DegradedServices:usize,
997
998 pub UnhealthyServices:usize,
999
1000 pub TotalChecks:usize,
1001
1002 pub AverageResponseTimeMs:f64,
1003
1004 pub SuccessRate:f64,
1005}
1006
1007impl HealthStatistics {
1008 pub fn OverallHealthPercentage(&self) -> f64 {
1010 if self.TotalServices == 0 {
1011 return 0.0;
1012 }
1013
1014 (self.HealthyServices as f64 / self.TotalServices as f64) * 100.0
1015 }
1016}
1017
1018#[derive(Debug, Clone, Serialize, Deserialize)]
1020pub struct HealthCheckResponse {
1021 pub OverallStatus:HealthStatus,
1022
1023 pub ServiceHealth:HashMap<String, ServiceHealth>,
1024
1025 pub Statistics:HealthStatistics,
1026
1027 pub PerformanceIndicators:PerformanceIndicators,
1028
1029 pub ResourceWarnings:Vec<ResourceWarning>,
1030
1031 pub Timestamp:u64,
1032}
1033
1034impl HealthCheckResponse {
1035 pub fn new(
1037 OverallStatus:HealthStatus,
1038
1039 ServiceHealth:HashMap<String, ServiceHealth>,
1040
1041 Statistics:HealthStatistics,
1042 ) -> Self {
1043 Self {
1044 OverallStatus,
1045
1046 ServiceHealth,
1047
1048 Statistics,
1049
1050 PerformanceIndicators:PerformanceIndicators::default(),
1051
1052 ResourceWarnings:Vec::new(),
1053
1054 Timestamp:Utility::CurrentTimestamp(),
1055 }
1056 }
1057
1058 pub fn with_performance_indicators(mut self, indicators:PerformanceIndicators) -> Self {
1060 self.PerformanceIndicators = indicators;
1061
1062 self
1063 }
1064
1065 pub fn with_resource_warnings(mut self, warnings:Vec<ResourceWarning>) -> Self {
1067 self.ResourceWarnings = warnings;
1068
1069 self
1070 }
1071}
1072
1073#[derive(Debug, Clone, Serialize, Deserialize)]
1075pub struct PerformanceIndicators {
1076 pub ResponseTimeP99Ms:f64,
1077
1078 pub ResponseTimeP95Ms:f64,
1079
1080 pub RequestThroughputPerSec:f64,
1081
1082 pub ErrorRatePercent:f64,
1083
1084 pub DegradationLevel:DegradationLevel,
1085
1086 pub BottleneckService:Option<String>,
1087}
1088
1089impl Default for PerformanceIndicators {
1090 fn default() -> Self {
1091 Self {
1092 ResponseTimeP99Ms:0.0,
1093
1094 ResponseTimeP95Ms:0.0,
1095
1096 RequestThroughputPerSec:0.0,
1097
1098 ErrorRatePercent:0.0,
1099
1100 DegradationLevel:DegradationLevel::Optimal,
1101
1102 BottleneckService:None,
1103 }
1104 }
1105}
1106
1107#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1109pub enum DegradationLevel {
1110 Optimal,
1111
1112 Acceptable,
1113
1114 Degraded,
1115
1116 Critical,
1117}
1118
1119#[derive(Debug, Clone, Serialize, Deserialize)]
1121pub struct ResourceWarning {
1122 pub WarningType:ResourceWarningType,
1123
1124 pub ServiceName:Option<String>,
1125
1126 pub CurrentValue:f64,
1127
1128 pub Threshold:f64,
1129
1130 pub Severity:WarningSeverity,
1131
1132 pub Timestamp:u64,
1133}
1134
1135#[derive(Debug, Clone, Serialize, Deserialize)]
1137pub enum ResourceWarningType {
1138 HighMemoryUsage,
1139
1140 HighCPUUsage,
1141
1142 LowDiskSpace,
1143
1144 ConnectionPoolExhausted,
1145
1146 ThreadPoolExhausted,
1147
1148 HighLatency,
1149
1150 HighErrorRate,
1151
1152 DatabaseConnectivityIssue,
1153}
1154
1155#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1157pub enum WarningSeverity {
1158 Low,
1159
1160 Medium,
1161
1162 High,
1163
1164 Critical,
1165}