1use parking_lot::RwLock;
7use std::collections::{HashMap, HashSet};
8use std::sync::Arc;
9use thiserror::Error;
10use tracing::{debug, info, warn};
11
12#[derive(Debug, Error)]
14pub enum DegradationError {
15 #[error("Feature not found: {0}")]
16 FeatureNotFound(String),
17 #[error("Feature already registered: {0}")]
18 FeatureAlreadyRegistered(String),
19 #[error("Fallback execution failed: {0}")]
20 FallbackFailed(String),
21 #[error("Feature is disabled: {0}")]
22 FeatureDisabled(String),
23}
24
25pub type FallbackFn = Arc<dyn Fn() -> Result<(), Box<dyn std::error::Error + Send + Sync>> + Send + Sync>;
27
28#[derive(Clone)]
30pub struct FeatureInfo {
31 pub name: String,
33 pub enabled: bool,
35 pub disable_count: u32,
37 pub enable_count: u32,
39 pub fallback_executions: u32,
41 pub description: Option<String>,
43}
44
45impl FeatureInfo {
46 pub fn new(name: String) -> Self {
48 Self {
49 name,
50 enabled: true,
51 disable_count: 0,
52 enable_count: 0,
53 fallback_executions: 0,
54 description: None,
55 }
56 }
57
58 pub fn with_description(mut self, description: String) -> Self {
60 self.description = Some(description);
61 self
62 }
63}
64
65pub struct DegradationManager {
67 disabled_features: RwLock<HashSet<String>>,
69 fallbacks: RwLock<HashMap<String, FallbackFn>>,
71 features: RwLock<HashMap<String, FeatureInfo>>,
73 dependencies: RwLock<HashMap<String, Vec<String>>>,
75}
76
77impl DegradationManager {
78 pub fn new() -> Self {
80 Self {
81 disabled_features: RwLock::new(HashSet::new()),
82 fallbacks: RwLock::new(HashMap::new()),
83 features: RwLock::new(HashMap::new()),
84 dependencies: RwLock::new(HashMap::new()),
85 }
86 }
87
88 pub fn register_feature(&self, name: String) -> Result<(), DegradationError> {
90 let mut features = self.features.write();
91 if features.contains_key(&name) {
92 return Err(DegradationError::FeatureAlreadyRegistered(name));
93 }
94 features.insert(name.clone(), FeatureInfo::new(name.clone()));
95 debug!("Registered feature: {}", name);
96 Ok(())
97 }
98
99 pub fn register_feature_with_description(
101 &self,
102 name: String,
103 description: String,
104 ) -> Result<(), DegradationError> {
105 let mut features = self.features.write();
106 if features.contains_key(&name) {
107 return Err(DegradationError::FeatureAlreadyRegistered(name));
108 }
109 features.insert(
110 name.clone(),
111 FeatureInfo::new(name.clone()).with_description(description),
112 );
113 debug!("Registered feature with description: {}", name);
114 Ok(())
115 }
116
117 pub fn disable_feature(&self, name: &str) -> Result<(), DegradationError> {
119 let mut features = self.features.write();
121 let feature = features
122 .get_mut(name)
123 .ok_or_else(|| DegradationError::FeatureNotFound(name.to_string()))?;
124
125 if feature.enabled {
126 feature.enabled = false;
127 feature.disable_count += 1;
128 drop(features);
129
130 self.disabled_features.write().insert(name.to_string());
131 warn!("Disabled feature: {}", name);
132
133 self.disable_dependents(name)?;
135 }
136
137 Ok(())
138 }
139
140 pub fn enable_feature(&self, name: &str) -> Result<(), DegradationError> {
142 let mut features = self.features.write();
144 let feature = features
145 .get_mut(name)
146 .ok_or_else(|| DegradationError::FeatureNotFound(name.to_string()))?;
147
148 if !feature.enabled {
149 feature.enabled = true;
150 feature.enable_count += 1;
151 drop(features);
152
153 self.disabled_features.write().remove(name);
154 info!("Enabled feature: {}", name);
155 }
156
157 Ok(())
158 }
159
160 pub fn is_enabled(&self, name: &str) -> bool {
162 !self.disabled_features.read().contains(name)
163 }
164
165 pub fn register_fallback<F>(&self, name: String, fallback: F) -> Result<(), DegradationError>
167 where
168 F: Fn() -> Result<(), Box<dyn std::error::Error + Send + Sync>> + Send + Sync + 'static,
169 {
170 if !self.features.read().contains_key(&name) {
172 self.register_feature(name.clone())?;
173 }
174
175 self.fallbacks
176 .write()
177 .insert(name.clone(), Arc::new(fallback));
178 debug!("Registered fallback for feature: {}", name);
179 Ok(())
180 }
181
182 pub fn execute_fallback(&self, name: &str) -> Result<(), DegradationError> {
184 if let Some(feature) = self.features.write().get_mut(name) {
186 feature.fallback_executions += 1;
187 }
188
189 let fallbacks = self.fallbacks.read();
190 let fallback = fallbacks
191 .get(name)
192 .ok_or_else(|| DegradationError::FeatureNotFound(name.to_string()))?;
193
194 debug!("Executing fallback for feature: {}", name);
195
196 fallback().map_err(|e| DegradationError::FallbackFailed(e.to_string()))
197 }
198
199 pub fn execute_with_fallback<F, T>(
201 &self,
202 feature_name: &str,
203 operation: F,
204 ) -> Result<T, DegradationError>
205 where
206 F: FnOnce() -> Result<T, Box<dyn std::error::Error + Send + Sync>>,
207 T: Default,
208 {
209 if self.is_enabled(feature_name) {
210 match operation() {
211 Ok(result) => Ok(result),
212 Err(e) => {
213 warn!("Operation failed for feature {}: {}", feature_name, e);
214 self.execute_fallback(feature_name)?;
215 Ok(T::default())
216 }
217 }
218 } else {
219 self.execute_fallback(feature_name)?;
220 Ok(T::default())
221 }
222 }
223
224 pub fn add_dependency(
226 &self,
227 feature: String,
228 depends_on: String,
229 ) -> Result<(), DegradationError> {
230 if !self.features.read().contains_key(&feature) {
232 return Err(DegradationError::FeatureNotFound(feature));
233 }
234 if !self.features.read().contains_key(&depends_on) {
235 return Err(DegradationError::FeatureNotFound(depends_on));
236 }
237
238 self.dependencies
239 .write()
240 .entry(depends_on.clone())
241 .or_default()
242 .push(feature.clone());
243
244 debug!("Added dependency: {} depends on {}", feature, depends_on);
245 Ok(())
246 }
247
248 fn disable_dependents(&self, feature: &str) -> Result<(), DegradationError> {
250 let dependencies = self.dependencies.read();
251 if let Some(dependents) = dependencies.get(feature) {
252 let dependents_clone = dependents.clone();
253 drop(dependencies);
254
255 for dependent in dependents_clone {
256 warn!(
257 "Disabling dependent feature {} because {} is disabled",
258 dependent, feature
259 );
260 self.disable_feature(&dependent)?;
261 }
262 }
263
264 Ok(())
265 }
266
267 pub fn feature_info(&self, name: &str) -> Result<FeatureInfo, DegradationError> {
269 self.features
270 .read()
271 .get(name)
272 .cloned()
273 .ok_or_else(|| DegradationError::FeatureNotFound(name.to_string()))
274 }
275
276 pub fn all_features(&self) -> HashMap<String, FeatureInfo> {
278 self.features.read().clone()
279 }
280
281 pub fn disabled_features(&self) -> Vec<String> {
283 self.disabled_features.read().iter().cloned().collect()
284 }
285
286 pub fn enabled_features(&self) -> Vec<String> {
288 let disabled = self.disabled_features.read();
289 self.features
290 .read()
291 .keys()
292 .filter(|k| !disabled.contains(*k))
293 .cloned()
294 .collect()
295 }
296
297 pub fn feature_count(&self) -> usize {
299 self.features.read().len()
300 }
301
302 pub fn disabled_count(&self) -> usize {
304 self.disabled_features.read().len()
305 }
306
307 pub fn clear(&self) {
309 self.features.write().clear();
310 self.disabled_features.write().clear();
311 self.fallbacks.write().clear();
312 self.dependencies.write().clear();
313 }
314
315 pub fn batch_disable(&self, features: &[&str]) -> Result<(), DegradationError> {
317 for feature in features {
318 self.disable_feature(feature)?;
319 }
320 Ok(())
321 }
322
323 pub fn batch_enable(&self, features: &[&str]) -> Result<(), DegradationError> {
325 for feature in features {
326 self.enable_feature(feature)?;
327 }
328 Ok(())
329 }
330}
331
332impl Default for DegradationManager {
333 fn default() -> Self {
334 Self::new()
335 }
336}
337
338#[cfg(test)]
339mod tests {
340 use super::*;
341 use std::sync::atomic::{AtomicU32, Ordering};
342
343 #[test]
344 fn test_degradation_manager_creation() {
345 let manager = DegradationManager::new();
346 assert_eq!(manager.feature_count(), 0);
347 assert_eq!(manager.disabled_count(), 0);
348 }
349
350 #[test]
351 fn test_register_feature() {
352 let manager = DegradationManager::new();
353 manager.register_feature("test-feature".to_string()).unwrap();
354 assert_eq!(manager.feature_count(), 1);
355 assert!(manager.is_enabled("test-feature"));
356 }
357
358 #[test]
359 fn test_register_duplicate_feature() {
360 let manager = DegradationManager::new();
361 manager.register_feature("test".to_string()).unwrap();
362 let result = manager.register_feature("test".to_string());
363 assert!(result.is_err());
364 }
365
366 #[test]
367 fn test_disable_feature() {
368 let manager = DegradationManager::new();
369 manager.register_feature("test".to_string()).unwrap();
370
371 assert!(manager.is_enabled("test"));
372 manager.disable_feature("test").unwrap();
373 assert!(!manager.is_enabled("test"));
374 assert_eq!(manager.disabled_count(), 1);
375 }
376
377 #[test]
378 fn test_enable_feature() {
379 let manager = DegradationManager::new();
380 manager.register_feature("test".to_string()).unwrap();
381
382 manager.disable_feature("test").unwrap();
383 assert!(!manager.is_enabled("test"));
384
385 manager.enable_feature("test").unwrap();
386 assert!(manager.is_enabled("test"));
387 assert_eq!(manager.disabled_count(), 0);
388 }
389
390 #[test]
391 fn test_disable_nonexistent_feature() {
392 let manager = DegradationManager::new();
393 let result = manager.disable_feature("nonexistent");
394 assert!(result.is_err());
395 }
396
397 #[test]
398 fn test_register_fallback() {
399 let manager = DegradationManager::new();
400 manager.register_feature("test".to_string()).unwrap();
401
402 let result = manager.register_fallback("test".to_string(), || Ok(()));
403 assert!(result.is_ok());
404 }
405
406 #[test]
407 fn test_execute_fallback() {
408 let manager = DegradationManager::new();
409 manager.register_feature("test".to_string()).unwrap();
410
411 let counter = Arc::new(AtomicU32::new(0));
412 let counter_clone = Arc::clone(&counter);
413
414 manager
415 .register_fallback("test".to_string(), move || {
416 counter_clone.fetch_add(1, Ordering::SeqCst);
417 Ok(())
418 })
419 .unwrap();
420
421 manager.execute_fallback("test").unwrap();
422 assert_eq!(counter.load(Ordering::SeqCst), 1);
423 }
424
425 #[test]
426 fn test_execute_fallback_failure() {
427 let manager = DegradationManager::new();
428 manager.register_feature("test".to_string()).unwrap();
429
430 manager
431 .register_fallback("test".to_string(), || {
432 Err("fallback error".into())
433 })
434 .unwrap();
435
436 let result = manager.execute_fallback("test");
437 assert!(result.is_err());
438 }
439
440 #[test]
441 fn test_execute_with_fallback_success() {
442 let manager = DegradationManager::new();
443 manager.register_feature("test".to_string()).unwrap();
444
445 let counter = Arc::new(AtomicU32::new(0));
446 let counter_clone = Arc::clone(&counter);
447
448 manager
449 .register_fallback("test".to_string(), move || {
450 counter_clone.fetch_add(1, Ordering::SeqCst);
451 Ok(())
452 })
453 .unwrap();
454
455 let result: Result<i32, DegradationError> =
456 manager.execute_with_fallback("test", || Ok(42));
457
458 assert_eq!(result.unwrap(), 42);
459 assert_eq!(counter.load(Ordering::SeqCst), 0); }
461
462 #[test]
463 fn test_execute_with_fallback_on_failure() {
464 let manager = DegradationManager::new();
465 manager.register_feature("test".to_string()).unwrap();
466
467 let counter = Arc::new(AtomicU32::new(0));
468 let counter_clone = Arc::clone(&counter);
469
470 manager
471 .register_fallback("test".to_string(), move || {
472 counter_clone.fetch_add(1, Ordering::SeqCst);
473 Ok(())
474 })
475 .unwrap();
476
477 let result: Result<i32, DegradationError> =
478 manager.execute_with_fallback("test", || Err("operation failed".into()));
479
480 assert_eq!(result.unwrap(), 0); assert_eq!(counter.load(Ordering::SeqCst), 1); }
483
484 #[test]
485 fn test_execute_with_fallback_when_disabled() {
486 let manager = DegradationManager::new();
487 manager.register_feature("test".to_string()).unwrap();
488
489 let counter = Arc::new(AtomicU32::new(0));
490 let counter_clone = Arc::clone(&counter);
491
492 manager
493 .register_fallback("test".to_string(), move || {
494 counter_clone.fetch_add(1, Ordering::SeqCst);
495 Ok(())
496 })
497 .unwrap();
498
499 manager.disable_feature("test").unwrap();
500
501 let result: Result<i32, DegradationError> =
502 manager.execute_with_fallback("test", || Ok(42));
503
504 assert_eq!(result.unwrap(), 0); assert_eq!(counter.load(Ordering::SeqCst), 1); }
507
508 #[test]
509 fn test_feature_dependencies() {
510 let manager = DegradationManager::new();
511 manager.register_feature("parent".to_string()).unwrap();
512 manager.register_feature("child".to_string()).unwrap();
513
514 manager
515 .add_dependency("child".to_string(), "parent".to_string())
516 .unwrap();
517
518 assert!(manager.is_enabled("parent"));
519 assert!(manager.is_enabled("child"));
520
521 manager.disable_feature("parent").unwrap();
523 assert!(!manager.is_enabled("parent"));
524 assert!(!manager.is_enabled("child"));
525 }
526
527 #[test]
528 fn test_feature_info() {
529 let manager = DegradationManager::new();
530 manager.register_feature("test".to_string()).unwrap();
531
532 let info = manager.feature_info("test").unwrap();
533 assert_eq!(info.name, "test");
534 assert!(info.enabled);
535 assert_eq!(info.disable_count, 0);
536 }
537
538 #[test]
539 fn test_feature_statistics() {
540 let manager = DegradationManager::new();
541 manager.register_feature("test".to_string()).unwrap();
542 manager.register_fallback("test".to_string(), || Ok(())).unwrap();
543
544 manager.disable_feature("test").unwrap();
545 manager.enable_feature("test").unwrap();
546 manager.disable_feature("test").unwrap();
547 manager.execute_fallback("test").unwrap();
548
549 let info = manager.feature_info("test").unwrap();
550 assert_eq!(info.disable_count, 2);
551 assert_eq!(info.enable_count, 1);
552 assert_eq!(info.fallback_executions, 1);
553 }
554
555 #[test]
556 fn test_disabled_features_list() {
557 let manager = DegradationManager::new();
558 manager.register_feature("feature1".to_string()).unwrap();
559 manager.register_feature("feature2".to_string()).unwrap();
560 manager.register_feature("feature3".to_string()).unwrap();
561
562 manager.disable_feature("feature1").unwrap();
563 manager.disable_feature("feature3").unwrap();
564
565 let disabled = manager.disabled_features();
566 assert_eq!(disabled.len(), 2);
567 assert!(disabled.contains(&"feature1".to_string()));
568 assert!(disabled.contains(&"feature3".to_string()));
569 }
570
571 #[test]
572 fn test_enabled_features_list() {
573 let manager = DegradationManager::new();
574 manager.register_feature("feature1".to_string()).unwrap();
575 manager.register_feature("feature2".to_string()).unwrap();
576 manager.register_feature("feature3".to_string()).unwrap();
577
578 manager.disable_feature("feature1").unwrap();
579
580 let enabled = manager.enabled_features();
581 assert_eq!(enabled.len(), 2);
582 assert!(enabled.contains(&"feature2".to_string()));
583 assert!(enabled.contains(&"feature3".to_string()));
584 }
585
586 #[test]
587 fn test_clear() {
588 let manager = DegradationManager::new();
589 manager.register_feature("test1".to_string()).unwrap();
590 manager.register_feature("test2".to_string()).unwrap();
591 manager.disable_feature("test1").unwrap();
592
593 assert_eq!(manager.feature_count(), 2);
594 assert_eq!(manager.disabled_count(), 1);
595
596 manager.clear();
597
598 assert_eq!(manager.feature_count(), 0);
599 assert_eq!(manager.disabled_count(), 0);
600 }
601
602 #[test]
603 fn test_batch_disable() {
604 let manager = DegradationManager::new();
605 manager.register_feature("f1".to_string()).unwrap();
606 manager.register_feature("f2".to_string()).unwrap();
607 manager.register_feature("f3".to_string()).unwrap();
608
609 manager.batch_disable(&["f1", "f2"]).unwrap();
610
611 assert!(!manager.is_enabled("f1"));
612 assert!(!manager.is_enabled("f2"));
613 assert!(manager.is_enabled("f3"));
614 assert_eq!(manager.disabled_count(), 2);
615 }
616
617 #[test]
618 fn test_batch_enable() {
619 let manager = DegradationManager::new();
620 manager.register_feature("f1".to_string()).unwrap();
621 manager.register_feature("f2".to_string()).unwrap();
622 manager.disable_feature("f1").unwrap();
623 manager.disable_feature("f2").unwrap();
624
625 manager.batch_enable(&["f1", "f2"]).unwrap();
626
627 assert!(manager.is_enabled("f1"));
628 assert!(manager.is_enabled("f2"));
629 assert_eq!(manager.disabled_count(), 0);
630 }
631
632 #[test]
633 fn test_feature_with_description() {
634 let manager = DegradationManager::new();
635 manager
636 .register_feature_with_description(
637 "test".to_string(),
638 "Test feature description".to_string(),
639 )
640 .unwrap();
641
642 let info = manager.feature_info("test").unwrap();
643 assert_eq!(
644 info.description,
645 Some("Test feature description".to_string())
646 );
647 }
648
649 #[test]
650 fn test_multiple_dependencies() {
651 let manager = DegradationManager::new();
652 manager.register_feature("parent".to_string()).unwrap();
653 manager.register_feature("child1".to_string()).unwrap();
654 manager.register_feature("child2".to_string()).unwrap();
655
656 manager
657 .add_dependency("child1".to_string(), "parent".to_string())
658 .unwrap();
659 manager
660 .add_dependency("child2".to_string(), "parent".to_string())
661 .unwrap();
662
663 manager.disable_feature("parent").unwrap();
664
665 assert!(!manager.is_enabled("child1"));
666 assert!(!manager.is_enabled("child2"));
667 }
668}