sz_orm_core/
degradation.rs1use std::collections::HashMap;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
9pub enum DegradationStrategy {
10 ReturnCache,
11 ReturnDefault,
12 FastFail,
13}
14
15impl DegradationStrategy {
16 pub fn as_str(&self) -> &'static str {
17 match self {
18 DegradationStrategy::ReturnCache => "return_cache",
19 DegradationStrategy::ReturnDefault => "return_default",
20 DegradationStrategy::FastFail => "fast_fail",
21 }
22 }
23}
24
25#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
26pub struct DegradationResult {
27 pub data: Option<Vec<HashMap<String, String>>>,
28 pub is_degraded: bool,
29 pub degradation_strategy: DegradationStrategy,
30 pub mismatch_warning: bool,
31}
32
33impl DegradationResult {
34 pub fn from_cache(data: Vec<HashMap<String, String>>) -> Self {
35 Self {
36 data: Some(data),
37 is_degraded: true,
38 degradation_strategy: DegradationStrategy::ReturnCache,
39 mismatch_warning: false,
40 }
41 }
42
43 pub fn from_default() -> Self {
44 Self {
45 data: Some(Vec::new()),
46 is_degraded: true,
47 degradation_strategy: DegradationStrategy::ReturnDefault,
48 mismatch_warning: false,
49 }
50 }
51
52 pub fn fast_fail() -> Self {
53 Self {
54 data: None,
55 is_degraded: true,
56 degradation_strategy: DegradationStrategy::FastFail,
57 mismatch_warning: false,
58 }
59 }
60
61 pub fn with_mismatch_warning(mut self) -> Self {
62 self.mismatch_warning = true;
63 self
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
68pub enum DegradationError {
69 #[error("cache miss for query fingerprint: {0}")]
70 CacheMiss(String),
71 #[error("fast fail: circuit breaker open")]
72 FastFail,
73 #[error("degradation data mismatch for query fingerprint: {0}")]
74 DataMismatch(String),
75}
76
77pub trait DegradationHandler: Send + Sync {
78 fn handle(&self, query_fingerprint: &str) -> Result<DegradationResult, DegradationError>;
79 fn strategy(&self) -> DegradationStrategy;
80}
81
82pub struct CacheDegradation {
83 cache: HashMap<String, Vec<HashMap<String, String>>>,
84}
85
86impl CacheDegradation {
87 pub fn new() -> Self {
89 Self {
90 cache: HashMap::new(),
91 }
92 }
93
94 pub fn with_cache(cache: HashMap<String, Vec<HashMap<String, String>>>) -> Self {
95 Self { cache }
96 }
97
98 pub fn insert(&mut self, fingerprint: String, data: Vec<HashMap<String, String>>) {
99 self.cache.insert(fingerprint, data);
100 }
101}
102
103impl Default for CacheDegradation {
104 fn default() -> Self {
105 Self::new()
106 }
107}
108
109impl DegradationHandler for CacheDegradation {
110 fn handle(&self, query_fingerprint: &str) -> Result<DegradationResult, DegradationError> {
111 match self.cache.get(query_fingerprint) {
112 Some(data) => Ok(DegradationResult::from_cache(data.clone())),
113 None => Err(DegradationError::CacheMiss(query_fingerprint.to_string())),
114 }
115 }
116
117 fn strategy(&self) -> DegradationStrategy {
118 DegradationStrategy::ReturnCache
119 }
120}
121
122pub struct DefaultDegradation;
123
124impl DefaultDegradation {
125 pub fn new() -> Self {
126 Self
127 }
128}
129
130impl Default for DefaultDegradation {
131 fn default() -> Self {
132 Self
133 }
134}
135
136impl DegradationHandler for DefaultDegradation {
137 fn handle(&self, _query_fingerprint: &str) -> Result<DegradationResult, DegradationError> {
138 Ok(DegradationResult::from_default())
139 }
140
141 fn strategy(&self) -> DegradationStrategy {
142 DegradationStrategy::ReturnDefault
143 }
144}
145
146pub struct FastFailDegradation;
147
148impl FastFailDegradation {
149 pub fn new() -> Self {
150 Self
151 }
152}
153
154impl Default for FastFailDegradation {
155 fn default() -> Self {
156 Self
157 }
158}
159
160impl DegradationHandler for FastFailDegradation {
161 fn handle(&self, _query_fingerprint: &str) -> Result<DegradationResult, DegradationError> {
162 Err(DegradationError::FastFail)
163 }
164
165 fn strategy(&self) -> DegradationStrategy {
166 DegradationStrategy::FastFail
167 }
168}
169
170pub fn execute_with_degradation(
172 can_execute: bool,
173 handler: &dyn DegradationHandler,
174 query_fingerprint: &str,
175 normal_query: impl FnOnce() -> Result<Vec<HashMap<String, String>>, String>,
176) -> Result<DegradationResult, DegradationError> {
177 if can_execute {
178 match normal_query() {
179 Ok(data) => Ok(DegradationResult {
180 data: Some(data),
181 is_degraded: false,
182 degradation_strategy: handler.strategy(),
183 mismatch_warning: false,
184 }),
185 Err(_) => handler.handle(query_fingerprint),
186 }
187 } else {
188 handler.handle(query_fingerprint)
189 }
190}