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			MaximumRetries:3,
65			RetryBaseDelay:Duration::from_millis(100),
66			RetryMaximumDelay:Duration::from_secs(10),
67			RetryJitterEnabled:true,
68			CircuitBreakerFailureThreshold:5,
69			CircuitBreakerResetTimeout:Duration::from_secs(60),
70			HealthChecksEnabled:true,
71			HealthCheckInterval:Duration::from_secs(30),
72			MetricsEnabled:true,
73			TransportConfigurations:HashMap::new(),
74			AllowedTransports:Vec::new(),
75			ForbiddenTransports:Vec::new(),
76		}
77	}
78}
79
80impl TransportConfig {
81	/// Creates a new `TransportConfig` with default values.
82	pub fn New() -> Self { Self::default() }
83
84	/// Sets the default request timeout.
85	pub fn WithDefaultTimeout(mut self, Timeout:Duration) -> Self {
86		self.DefaultTimeout = Timeout;
87		self
88	}
89
90	/// Sets the maximum number of retry attempts.
91	pub fn WithMaximumRetries(mut self, MaximumRetries:u32) -> Self {
92		self.MaximumRetries = MaximumRetries;
93		self
94	}
95
96	/// Sets the base retry delay for exponential backoff.
97	pub fn WithRetryBaseDelay(mut self, Delay:Duration) -> Self {
98		self.RetryBaseDelay = Delay;
99		self
100	}
101
102	/// Sets the maximum retry delay cap.
103	pub fn WithRetryMaximumDelay(mut self, Delay:Duration) -> Self {
104		self.RetryMaximumDelay = Delay;
105		self
106	}
107
108	/// Enables or disables retry jitter.
109	pub fn WithRetryJitter(mut self, Enabled:bool) -> Self {
110		self.RetryJitterEnabled = Enabled;
111		self
112	}
113
114	/// Sets the circuit breaker failure threshold.
115	pub fn WithCircuitBreakerThreshold(mut self, Threshold:u32) -> Self {
116		self.CircuitBreakerFailureThreshold = Threshold;
117		self
118	}
119
120	/// Sets the circuit breaker reset timeout.
121	pub fn WithCircuitBreakerResetTimeout(mut self, Timeout:Duration) -> Self {
122		self.CircuitBreakerResetTimeout = Timeout;
123		self
124	}
125
126	/// Enables or disables health checks.
127	pub fn WithHealthChecksEnabled(mut self, Enabled:bool) -> Self {
128		self.HealthChecksEnabled = Enabled;
129		self
130	}
131
132	/// Sets the health check interval.
133	pub fn WithHealthCheckInterval(mut self, Interval:Duration) -> Self {
134		self.HealthCheckInterval = Interval;
135		self
136	}
137
138	/// Enables or disables metrics collection.
139	pub fn WithMetricsEnabled(mut self, Enabled:bool) -> Self {
140		self.MetricsEnabled = Enabled;
141		self
142	}
143
144	/// Adds a transport-specific configuration override.
145	pub fn WithTransportConfiguration(mut self, TransportKind:TransportType, Configuration:serde_json::Value) -> Self {
146		self.TransportConfigurations.insert(TransportKind, Configuration);
147		self
148	}
149
150	/// Gets the transport-specific configuration for the given type, if any.
151	pub fn GetTransportConfiguration(&self, TransportKind:TransportType) -> Option<&serde_json::Value> {
152		self.TransportConfigurations.get(&TransportKind)
153	}
154
155	/// Sets the allowed transport types for auto-selection.
156	pub fn WithAllowedTransports(mut self, Transports:Vec<TransportType>) -> Self {
157		self.AllowedTransports = Transports;
158		self
159	}
160
161	/// Adds a forbidden transport type.
162	pub fn AddForbiddenTransport(mut self, TransportKind:TransportType) -> Self {
163		self.ForbiddenTransports.push(TransportKind);
164		self
165	}
166
167	/// Alias for `AddForbiddenTransport`.
168	pub fn WithForbiddenTransport(self, TransportKind:TransportType) -> Self {
169		self.AddForbiddenTransport(TransportKind)
170	}
171
172	/// Checks if a transport type is allowed by this configuration.
173	pub fn IsAllowed(&self, TransportKind:TransportType) -> bool {
174		if self.ForbiddenTransports.contains(&TransportKind) {
175			return false;
176		}
177		if self.AllowedTransports.is_empty() {
178			true
179		} else {
180			self.AllowedTransports.contains(&TransportKind)
181		}
182	}
183
184	/// Gets the effective timeout for a request, considering request-specific
185	/// overrides.
186	pub fn EffectiveTimeout(&self, RequestTimeoutMilliseconds:Option<u64>) -> Duration {
187		RequestTimeoutMilliseconds
188			.map(Duration::from_millis)
189			.unwrap_or(self.DefaultTimeout)
190	}
191
192	/// Gets the effective retry delay for a given attempt number, considering
193	/// jitter.
194	pub fn EffectiveRetryDelay(&self, Attempt:u32) -> Duration {
195		let Multiplier = 1u32.checked_shl(Attempt.min(30)).unwrap_or(u32::MAX);
196		let mut Delay = self.RetryBaseDelay.checked_mul(Multiplier).unwrap_or(self.RetryMaximumDelay);
197
198		if Delay > self.RetryMaximumDelay {
199			Delay = self.RetryMaximumDelay;
200		}
201
202		if self.RetryJitterEnabled {
203			let Nanoseconds = std::time::SystemTime::now()
204				.duration_since(std::time::UNIX_EPOCH)
205				.map(|Duration| Duration.subsec_nanos())
206				.unwrap_or(0);
207			let JitterFraction = (Nanoseconds % 1000) as f64 / 500.0 - 1.0;
208			let JitterAmount = Delay.as_millis() as f64 * 0.25;
209			let AdjustedMilliseconds = (Delay.as_millis() as f64 + JitterFraction * JitterAmount).max(1.0) as u64;
210			Delay = Duration::from_millis(AdjustedMilliseconds);
211		}
212
213		Delay
214	}
215}
216
217#[cfg(test)]
218mod tests {
219	use super::*;
220
221	#[test]
222	fn TestTransportConfigDefaults() {
223		let Configuration = TransportConfig::default();
224		assert_eq!(Configuration.DefaultTimeout, Duration::from_secs(30));
225		assert_eq!(Configuration.MaximumRetries, 3);
226		assert!(Configuration.HealthChecksEnabled);
227		assert!(Configuration.MetricsEnabled);
228	}
229
230	#[test]
231	fn TestTransportConfigBuilder() {
232		let Configuration = TransportConfig::default()
233			.WithDefaultTimeout(Duration::from_secs(60))
234			.WithMaximumRetries(5)
235			.WithRetryJitter(false);
236
237		assert_eq!(Configuration.DefaultTimeout, Duration::from_secs(60));
238		assert_eq!(Configuration.MaximumRetries, 5);
239		assert!(!Configuration.RetryJitterEnabled);
240	}
241
242	#[test]
243	fn TestIsAllowed() {
244		let Configuration = TransportConfig::default();
245		assert!(Configuration.IsAllowed(TransportType::Grpc));
246
247		let Configuration = Configuration.WithForbiddenTransport(TransportType::Grpc);
248		assert!(!Configuration.IsAllowed(TransportType::Grpc));
249		assert!(Configuration.IsAllowed(TransportType::Ipc));
250
251		let Configuration = Configuration.WithAllowedTransports(vec![TransportType::Ipc]);
252		assert!(!Configuration.IsAllowed(TransportType::Grpc));
253		assert!(Configuration.IsAllowed(TransportType::Ipc));
254	}
255
256	#[test]
257	fn TestEffectiveTimeout() {
258		let Configuration = TransportConfig::default().WithDefaultTimeout(Duration::from_secs(30));
259
260		assert_eq!(Configuration.EffectiveTimeout(None), Duration::from_secs(30));
261		assert_eq!(Configuration.EffectiveTimeout(Some(5000)), Duration::from_millis(5000));
262	}
263
264	#[test]
265	fn TestEffectiveRetryDelay() {
266		let Configuration = TransportConfig::default()
267			.WithRetryBaseDelay(Duration::from_millis(100))
268			.WithRetryMaximumDelay(Duration::from_secs(10))
269			.WithRetryJitter(false);
270
271		assert_eq!(Configuration.EffectiveRetryDelay(0), Duration::from_millis(100));
272		assert_eq!(Configuration.EffectiveRetryDelay(1), Duration::from_millis(200));
273		assert_eq!(Configuration.EffectiveRetryDelay(2), Duration::from_millis(400));
274		assert_eq!(Configuration.EffectiveRetryDelay(10), Duration::from_secs(10));
275	}
276}