1use std::{net::SocketAddr, time::Duration};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct RpcClientConfig {
6 pub endpoint: String,
8 pub connect_timeout: Duration,
10 pub request_timeout: Duration,
12 pub resilience: RpcResilienceConfig,
14 pub retry: RpcRetryConfig,
16 pub deadline: RpcDeadlineConfig,
18 pub load_balance: RpcLoadBalanceConfig,
20 pub discovery: RpcDiscoveryConfig,
22 pub streaming: RpcStreamingConfig,
24}
25
26impl RpcClientConfig {
27 pub fn new(endpoint: impl Into<String>) -> Self {
29 Self {
30 endpoint: endpoint.into(),
31 connect_timeout: Duration::from_secs(3),
32 request_timeout: Duration::from_secs(5),
33 resilience: RpcResilienceConfig::default(),
34 retry: RpcRetryConfig::default(),
35 deadline: RpcDeadlineConfig::default(),
36 load_balance: RpcLoadBalanceConfig::default(),
37 discovery: RpcDiscoveryConfig::default(),
38 streaming: RpcStreamingConfig::default(),
39 }
40 }
41}
42
43impl RpcClientConfig {
44 pub fn production_defaults(endpoint: impl Into<String>) -> Self {
46 Self {
47 resilience: RpcResilienceConfig::production_defaults(),
48 retry: RpcRetryConfig::production_defaults(),
49 deadline: RpcDeadlineConfig::production_defaults(),
50 load_balance: RpcLoadBalanceConfig::production_defaults(),
51 streaming: RpcStreamingConfig::production_defaults(),
52 ..Self::new(endpoint)
53 }
54 }
55
56 #[allow(deprecated)]
58 #[deprecated(note = "use production_defaults instead")]
59 pub fn go_zero_defaults(endpoint: impl Into<String>) -> Self {
60 Self::production_defaults(endpoint)
61 }
62}
63
64#[derive(Debug, Clone, PartialEq, Eq)]
66pub struct RpcServerConfig {
67 pub name: String,
69 pub addr: SocketAddr,
71 pub resilience: RpcResilienceConfig,
73 pub streaming: RpcStreamingConfig,
75}
76
77impl RpcServerConfig {
78 pub fn new(name: impl Into<String>, addr: SocketAddr) -> Self {
80 Self {
81 name: name.into(),
82 addr,
83 resilience: RpcResilienceConfig::default(),
84 streaming: RpcStreamingConfig::default(),
85 }
86 }
87}
88
89impl RpcServerConfig {
90 pub fn production_defaults(name: impl Into<String>, addr: SocketAddr) -> Self {
92 Self {
93 resilience: RpcResilienceConfig::production_defaults(),
94 streaming: RpcStreamingConfig::production_defaults(),
95 ..Self::new(name, addr)
96 }
97 }
98
99 #[allow(deprecated)]
101 #[deprecated(note = "use production_defaults instead")]
102 pub fn go_zero_defaults(name: impl Into<String>, addr: SocketAddr) -> Self {
103 Self::production_defaults(name, addr)
104 }
105}
106
107#[derive(Debug, Clone, PartialEq, Eq)]
109pub struct RpcRetryConfig {
110 pub enabled: bool,
112 pub max_attempts: u32,
114 pub initial_backoff: Duration,
116 pub max_backoff: Duration,
118 pub retryable_codes: Vec<tonic::Code>,
120}
121
122impl Default for RpcRetryConfig {
123 fn default() -> Self {
124 Self {
125 enabled: false,
126 max_attempts: 1,
127 initial_backoff: Duration::from_millis(50),
128 max_backoff: Duration::from_secs(1),
129 retryable_codes: vec![
130 tonic::Code::Unavailable,
131 tonic::Code::DeadlineExceeded,
132 tonic::Code::ResourceExhausted,
133 ],
134 }
135 }
136}
137
138impl RpcRetryConfig {
139 pub fn production_defaults() -> Self {
141 Self {
142 enabled: true,
143 max_attempts: 3,
144 initial_backoff: Duration::from_millis(50),
145 max_backoff: Duration::from_millis(500),
146 ..Self::default()
147 }
148 }
149
150 #[allow(deprecated)]
152 #[deprecated(note = "use production_defaults instead")]
153 pub fn go_zero_defaults() -> Self {
154 Self::production_defaults()
155 }
156}
157
158#[derive(Debug, Clone, PartialEq, Eq)]
160pub struct RpcDeadlineConfig {
161 pub propagate: bool,
163 pub clip_retries_to_budget: bool,
165}
166
167impl Default for RpcDeadlineConfig {
168 fn default() -> Self {
169 Self {
170 propagate: false,
171 clip_retries_to_budget: true,
172 }
173 }
174}
175
176impl RpcDeadlineConfig {
177 pub fn production_defaults() -> Self {
179 Self {
180 propagate: true,
181 clip_retries_to_budget: true,
182 }
183 }
184
185 #[allow(deprecated)]
187 #[deprecated(note = "use production_defaults instead")]
188 pub fn go_zero_defaults() -> Self {
189 Self::production_defaults()
190 }
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
195pub enum LoadBalancePolicy {
196 #[default]
198 Static,
199 WeightedRoundRobin,
201}
202
203#[derive(Debug, Clone, PartialEq, Eq, Default)]
205pub struct RpcLoadBalanceConfig {
206 pub policy: LoadBalancePolicy,
208}
209
210impl RpcLoadBalanceConfig {
211 pub fn production_defaults() -> Self {
213 Self {
214 policy: LoadBalancePolicy::WeightedRoundRobin,
215 }
216 }
217
218 #[allow(deprecated)]
220 #[deprecated(note = "use production_defaults instead")]
221 pub fn go_zero_defaults() -> Self {
222 Self::production_defaults()
223 }
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Default)]
228pub struct RpcDiscoveryConfig {
229 pub service: Option<String>,
231}
232
233#[derive(Debug, Clone, PartialEq, Eq, Default)]
235pub struct RpcStreamingConfig {
236 pub observe: bool,
238 pub resilience: bool,
240 pub timeout: Option<Duration>,
242}
243
244impl RpcStreamingConfig {
245 pub fn production_defaults() -> Self {
247 Self {
248 observe: true,
249 resilience: true,
250 timeout: Some(Duration::from_secs(30)),
251 }
252 }
253
254 #[allow(deprecated)]
256 #[deprecated(note = "use production_defaults instead")]
257 pub fn go_zero_defaults() -> Self {
258 Self::production_defaults()
259 }
260}
261
262#[derive(Debug, Clone, PartialEq, Eq)]
264pub struct RpcResilienceConfig {
265 pub breaker_enabled: bool,
267 pub breaker_failure_threshold: u32,
269 pub breaker_reset_timeout: Duration,
271 pub breaker_sre_enabled: bool,
273 pub breaker_sre_k_millis: u32,
275 pub breaker_sre_protection: u64,
277 pub max_concurrency: Option<usize>,
279 pub request_timeout: Duration,
281 pub shedding_enabled: bool,
283 pub shedding_max_in_flight: Option<usize>,
285 pub shedding_min_request_count: u64,
287 pub shedding_max_latency: Duration,
289 pub shedding_cpu_threshold_millis: u32,
291 pub shedding_cool_off: Duration,
293 pub shedding_window_buckets: usize,
295 pub shedding_window_bucket_duration: Duration,
297 #[cfg(all(feature = "resil", feature = "cache-redis"))]
299 pub rate_limiter: RpcRateLimiterConfig,
300}
301
302impl Default for RpcResilienceConfig {
303 fn default() -> Self {
304 Self {
305 breaker_enabled: false,
306 breaker_failure_threshold: 5,
307 breaker_reset_timeout: Duration::from_secs(30),
308 breaker_sre_enabled: false,
309 breaker_sre_k_millis: 1500,
310 breaker_sre_protection: 5,
311 max_concurrency: None,
312 request_timeout: Duration::from_secs(5),
313 shedding_enabled: false,
314 shedding_max_in_flight: None,
315 shedding_min_request_count: 20,
316 shedding_max_latency: Duration::from_millis(250),
317 shedding_cpu_threshold_millis: 900,
318 shedding_cool_off: Duration::from_secs(1),
319 shedding_window_buckets: 50,
320 shedding_window_bucket_duration: Duration::from_millis(100),
321 #[cfg(all(feature = "resil", feature = "cache-redis"))]
322 rate_limiter: RpcRateLimiterConfig::default(),
323 }
324 }
325}
326
327impl RpcResilienceConfig {
328 pub fn production_defaults() -> Self {
330 Self {
331 breaker_enabled: true,
332 breaker_sre_enabled: true,
333 max_concurrency: Some(1024),
334 request_timeout: Duration::from_secs(5),
335 shedding_enabled: true,
336 shedding_max_in_flight: Some(1024),
337 shedding_min_request_count: 20,
338 shedding_max_latency: Duration::from_millis(250),
339 ..Self::default()
340 }
341 }
342
343 #[allow(deprecated)]
345 #[deprecated(note = "use production_defaults instead")]
346 pub fn go_zero_defaults() -> Self {
347 Self::production_defaults()
348 }
349}
350
351#[cfg(all(feature = "resil", feature = "cache-redis"))]
353#[derive(Debug, Clone, PartialEq, Eq, Default)]
354pub enum RpcRateLimiterConfig {
355 #[default]
357 Disabled,
358 RedisToken(crate::resil::RedisTokenLimiterConfig),
360 RedisPeriod(crate::resil::RedisPeriodLimiterConfig),
362}