Skip to main content

CommonLibrary/Transport/
TransportConfig.rs

1#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
2//! # TransportConfig
3//!
4//! Configuration structures for transport implementations.
5
6use std::{collections::HashMap, time::Duration};
7
8use serde::{Deserialize, Serialize};
9
10use super::Common::TransportType;
11
12/// Global transport configuration.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct TransportConfig {
15	/// Default timeout for requests that don't specify one.
16	pub DefaultTimeout:Duration,
17
18	/// Maximum number of retry attempts for retryable errors.
19	pub MaximumRetries:u32,
20
21	/// Base retry delay for exponential backoff.
22	pub RetryBaseDelay:Duration,
23
24	/// Maximum retry delay cap (prevents extremely long backoffs).
25	pub RetryMaximumDelay:Duration,
26
27	/// Whether retry with jitter is enabled (recommended for distributed
28	/// systems).
29	pub RetryJitterEnabled:bool,
30
31	/// Circuit breaker failure threshold (number of consecutive failures before
32	/// opening).
33	pub CircuitBreakerFailureThreshold:u32,
34
35	/// Circuit breaker reset timeout (how long to wait before half-open).
36	pub CircuitBreakerResetTimeout:Duration,
37
38	/// Whether health checks are enabled.
39	pub HealthChecksEnabled:bool,
40
41	/// Health check interval (how often to perform health checks).
42	pub HealthCheckInterval:Duration,
43
44	/// Metrics collection enabled flag.
45	pub MetricsEnabled:bool,
46
47	/// Transport-specific configuration overrides.
48	#[serde(skip_serializing_if = "HashMap::is_empty")]
49	pub TransportConfigurations:HashMap<TransportType, serde_json::Value>,
50
51	/// Allowed transport types for auto-selection.
52	#[serde(skip_serializing_if = "Vec::is_empty")]
53	pub AllowedTransports:Vec<TransportType>,
54
55	/// Forbidden transport types (never used even if available).
56	#[serde(skip_serializing_if = "Vec::is_empty")]
57	pub ForbiddenTransports:Vec<TransportType>,
58}
59
60impl Default for TransportConfig {
61	fn default() -> Self {
62		Self {
63			DefaultTimeout:Duration::from_secs(30),
64
65			MaximumRetries:3,
66
67			RetryBaseDelay:Duration::from_millis(100),
68
69			RetryMaximumDelay:Duration::from_secs(10),
70
71			RetryJitterEnabled:true,
72
73			CircuitBreakerFailureThreshold:5,
74
75			CircuitBreakerResetTimeout:Duration::from_secs(60),
76
77			HealthChecksEnabled:true,
78
79			HealthCheckInterval:Duration::from_secs(30),
80
81			MetricsEnabled:true,
82
83			TransportConfigurations:HashMap::new(),
84
85			AllowedTransports:Vec::new(),
86
87			ForbiddenTransports:Vec::new(),
88		}
89	}
90}
91
92impl TransportConfig {
93	/// Creates a new `TransportConfig` with default values.
94	pub fn New() -> Self { Self::default() }
95
96	/// Sets the default request timeout.
97	pub fn WithDefaultTimeout(mut self, Timeout:Duration) -> Self {
98		self.DefaultTimeout = Timeout;
99
100		self
101	}
102
103	/// Sets the maximum number of retry attempts.
104	pub fn WithMaximumRetries(mut self, MaximumRetries:u32) -> Self {
105		self.MaximumRetries = MaximumRetries;
106
107		self
108	}
109
110	/// Sets the base retry delay for exponential backoff.
111	pub fn WithRetryBaseDelay(mut self, Delay:Duration) -> Self {
112		self.RetryBaseDelay = Delay;
113
114		self
115	}
116
117	/// Sets the maximum retry delay cap.
118	pub fn WithRetryMaximumDelay(mut self, Delay:Duration) -> Self {
119		self.RetryMaximumDelay = Delay;
120
121		self
122	}
123
124	/// Enables or disables retry jitter.
125	pub fn WithRetryJitter(mut self, Enabled:bool) -> Self {
126		self.RetryJitterEnabled = Enabled;
127
128		self
129	}
130
131	/// Sets the circuit breaker failure threshold.
132	pub fn WithCircuitBreakerThreshold(mut self, Threshold:u32) -> Self {
133		self.CircuitBreakerFailureThreshold = Threshold;
134
135		self
136	}
137
138	/// Sets the circuit breaker reset timeout.
139	pub fn WithCircuitBreakerResetTimeout(mut self, Timeout:Duration) -> Self {
140		self.CircuitBreakerResetTimeout = Timeout;
141
142		self
143	}
144
145	/// Enables or disables health checks.
146	pub fn WithHealthChecksEnabled(mut self, Enabled:bool) -> Self {
147		self.HealthChecksEnabled = Enabled;
148
149		self
150	}
151
152	/// Sets the health check interval.
153	pub fn WithHealthCheckInterval(mut self, Interval:Duration) -> Self {
154		self.HealthCheckInterval = Interval;
155
156		self
157	}
158
159	/// Enables or disables metrics collection.
160	pub fn WithMetricsEnabled(mut self, Enabled:bool) -> Self {
161		self.MetricsEnabled = Enabled;
162
163		self
164	}
165
166	/// Adds a transport-specific configuration override.
167	pub fn WithTransportConfiguration(mut self, TransportKind:TransportType, Configuration:serde_json::Value) -> Self {
168		self.TransportConfigurations.insert(TransportKind, Configuration);
169
170		self
171	}
172
173	/// Gets the transport-specific configuration for the given type, if any.
174	pub fn GetTransportConfiguration(&self, TransportKind:TransportType) -> Option<&serde_json::Value> {
175		self.TransportConfigurations.get(&TransportKind)
176	}
177
178	/// Sets the allowed transport types for auto-selection.
179	pub fn WithAllowedTransports(mut self, Transports:Vec<TransportType>) -> Self {
180		self.AllowedTransports = Transports;
181
182		self
183	}
184
185	/// Adds a forbidden transport type.
186	pub fn AddForbiddenTransport(mut self, TransportKind:TransportType) -> Self {
187		self.ForbiddenTransports.push(TransportKind);
188
189		self
190	}
191
192	/// Alias for `AddForbiddenTransport`.
193	pub fn WithForbiddenTransport(self, TransportKind:TransportType) -> Self {
194		self.AddForbiddenTransport(TransportKind)
195	}
196
197	/// Checks if a transport type is allowed by this configuration.
198	pub fn IsAllowed(&self, TransportKind:TransportType) -> bool {
199		if self.ForbiddenTransports.contains(&TransportKind) {
200			return false;
201		}
202
203		if self.AllowedTransports.is_empty() {
204			true
205		} else {
206			self.AllowedTransports.contains(&TransportKind)
207		}
208	}
209
210	/// Gets the effective timeout for a request, considering request-specific
211	/// overrides.
212	pub fn EffectiveTimeout(&self, RequestTimeoutMilliseconds:Option<u64>) -> Duration {
213		RequestTimeoutMilliseconds
214			.map(Duration::from_millis)
215			.unwrap_or(self.DefaultTimeout)
216	}
217
218	/// Gets the effective retry delay for a given attempt number, considering
219	/// jitter.
220	pub fn EffectiveRetryDelay(&self, Attempt:u32) -> Duration {
221		let Multiplier = 1u32.checked_shl(Attempt.min(30)).unwrap_or(u32::MAX);
222
223		let mut Delay = self.RetryBaseDelay.checked_mul(Multiplier).unwrap_or(self.RetryMaximumDelay);
224
225		if Delay > self.RetryMaximumDelay {
226			Delay = self.RetryMaximumDelay;
227		}
228
229		if self.RetryJitterEnabled {
230			let Nanoseconds = std::time::SystemTime::now()
231				.duration_since(std::time::UNIX_EPOCH)
232				.map(|Duration| Duration.subsec_nanos())
233				.unwrap_or(0);
234
235			let JitterFraction = (Nanoseconds % 1000) as f64 / 500.0 - 1.0;
236
237			let JitterAmount = Delay.as_millis() as f64 * 0.25;
238
239			let AdjustedMilliseconds = (Delay.as_millis() as f64 + JitterFraction * JitterAmount).max(1.0) as u64;
240
241			Delay = Duration::from_millis(AdjustedMilliseconds);
242		}
243
244		Delay
245	}
246}
247
248#[cfg(test)]
249mod tests {
250
251	use super::*;
252
253	#[test]
254	fn TestTransportConfigDefaults() {
255		let Configuration = TransportConfig::default();
256
257		assert_eq!(Configuration.DefaultTimeout, Duration::from_secs(30));
258
259		assert_eq!(Configuration.MaximumRetries, 3);
260
261		assert!(Configuration.HealthChecksEnabled);
262
263		assert!(Configuration.MetricsEnabled);
264	}
265
266	#[test]
267	fn TestTransportConfigBuilder() {
268		let Configuration = TransportConfig::default()
269			.WithDefaultTimeout(Duration::from_secs(60))
270			.WithMaximumRetries(5)
271			.WithRetryJitter(false);
272
273		assert_eq!(Configuration.DefaultTimeout, Duration::from_secs(60));
274
275		assert_eq!(Configuration.MaximumRetries, 5);
276
277		assert!(!Configuration.RetryJitterEnabled);
278	}
279
280	#[test]
281	fn TestIsAllowed() {
282		let Configuration = TransportConfig::default();
283
284		assert!(Configuration.IsAllowed(TransportType::Grpc));
285
286		let Configuration = Configuration.WithForbiddenTransport(TransportType::Grpc);
287
288		assert!(!Configuration.IsAllowed(TransportType::Grpc));
289
290		assert!(Configuration.IsAllowed(TransportType::Ipc));
291
292		let Configuration = Configuration.WithAllowedTransports(vec![TransportType::Ipc]);
293
294		assert!(!Configuration.IsAllowed(TransportType::Grpc));
295
296		assert!(Configuration.IsAllowed(TransportType::Ipc));
297	}
298
299	#[test]
300	fn TestEffectiveTimeout() {
301		let Configuration = TransportConfig::default().WithDefaultTimeout(Duration::from_secs(30));
302
303		assert_eq!(Configuration.EffectiveTimeout(None), Duration::from_secs(30));
304
305		assert_eq!(Configuration.EffectiveTimeout(Some(5000)), Duration::from_millis(5000));
306	}
307
308	#[test]
309	fn TestEffectiveRetryDelay() {
310		let Configuration = TransportConfig::default()
311			.WithRetryBaseDelay(Duration::from_millis(100))
312			.WithRetryMaximumDelay(Duration::from_secs(10))
313			.WithRetryJitter(false);
314
315		assert_eq!(Configuration.EffectiveRetryDelay(0), Duration::from_millis(100));
316
317		assert_eq!(Configuration.EffectiveRetryDelay(1), Duration::from_millis(200));
318
319		assert_eq!(Configuration.EffectiveRetryDelay(2), Duration::from_millis(400));
320
321		assert_eq!(Configuration.EffectiveRetryDelay(10), Duration::from_secs(10));
322	}
323}