use std::{net::SocketAddr, time::Duration};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RpcClientConfig {
pub endpoint: String,
pub connect_timeout: Duration,
pub request_timeout: Duration,
pub resilience: RpcResilienceConfig,
pub retry: RpcRetryConfig,
pub deadline: RpcDeadlineConfig,
pub load_balance: RpcLoadBalanceConfig,
pub discovery: RpcDiscoveryConfig,
pub streaming: RpcStreamingConfig,
}
impl RpcClientConfig {
pub fn new(endpoint: impl Into<String>) -> Self {
Self {
endpoint: endpoint.into(),
connect_timeout: Duration::from_secs(3),
request_timeout: Duration::from_secs(5),
resilience: RpcResilienceConfig::default(),
retry: RpcRetryConfig::default(),
deadline: RpcDeadlineConfig::default(),
load_balance: RpcLoadBalanceConfig::default(),
discovery: RpcDiscoveryConfig::default(),
streaming: RpcStreamingConfig::default(),
}
}
}
impl RpcClientConfig {
pub fn production_defaults(endpoint: impl Into<String>) -> Self {
Self {
resilience: RpcResilienceConfig::production_defaults(),
retry: RpcRetryConfig::production_defaults(),
deadline: RpcDeadlineConfig::production_defaults(),
load_balance: RpcLoadBalanceConfig::production_defaults(),
streaming: RpcStreamingConfig::production_defaults(),
..Self::new(endpoint)
}
}
#[allow(deprecated)]
#[deprecated(note = "use production_defaults instead")]
pub fn go_zero_defaults(endpoint: impl Into<String>) -> Self {
Self::production_defaults(endpoint)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RpcServerConfig {
pub name: String,
pub addr: SocketAddr,
pub resilience: RpcResilienceConfig,
pub streaming: RpcStreamingConfig,
}
impl RpcServerConfig {
pub fn new(name: impl Into<String>, addr: SocketAddr) -> Self {
Self {
name: name.into(),
addr,
resilience: RpcResilienceConfig::default(),
streaming: RpcStreamingConfig::default(),
}
}
}
impl RpcServerConfig {
pub fn production_defaults(name: impl Into<String>, addr: SocketAddr) -> Self {
Self {
resilience: RpcResilienceConfig::production_defaults(),
streaming: RpcStreamingConfig::production_defaults(),
..Self::new(name, addr)
}
}
#[allow(deprecated)]
#[deprecated(note = "use production_defaults instead")]
pub fn go_zero_defaults(name: impl Into<String>, addr: SocketAddr) -> Self {
Self::production_defaults(name, addr)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RpcRetryConfig {
pub enabled: bool,
pub max_attempts: u32,
pub initial_backoff: Duration,
pub max_backoff: Duration,
pub retryable_codes: Vec<tonic::Code>,
}
impl Default for RpcRetryConfig {
fn default() -> Self {
Self {
enabled: false,
max_attempts: 1,
initial_backoff: Duration::from_millis(50),
max_backoff: Duration::from_secs(1),
retryable_codes: vec![
tonic::Code::Unavailable,
tonic::Code::DeadlineExceeded,
tonic::Code::ResourceExhausted,
],
}
}
}
impl RpcRetryConfig {
pub fn production_defaults() -> Self {
Self {
enabled: true,
max_attempts: 3,
initial_backoff: Duration::from_millis(50),
max_backoff: Duration::from_millis(500),
..Self::default()
}
}
#[allow(deprecated)]
#[deprecated(note = "use production_defaults instead")]
pub fn go_zero_defaults() -> Self {
Self::production_defaults()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RpcDeadlineConfig {
pub propagate: bool,
pub clip_retries_to_budget: bool,
}
impl Default for RpcDeadlineConfig {
fn default() -> Self {
Self {
propagate: false,
clip_retries_to_budget: true,
}
}
}
impl RpcDeadlineConfig {
pub fn production_defaults() -> Self {
Self {
propagate: true,
clip_retries_to_budget: true,
}
}
#[allow(deprecated)]
#[deprecated(note = "use production_defaults instead")]
pub fn go_zero_defaults() -> Self {
Self::production_defaults()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum LoadBalancePolicy {
#[default]
Static,
WeightedRoundRobin,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct RpcLoadBalanceConfig {
pub policy: LoadBalancePolicy,
}
impl RpcLoadBalanceConfig {
pub fn production_defaults() -> Self {
Self {
policy: LoadBalancePolicy::WeightedRoundRobin,
}
}
#[allow(deprecated)]
#[deprecated(note = "use production_defaults instead")]
pub fn go_zero_defaults() -> Self {
Self::production_defaults()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct RpcDiscoveryConfig {
pub service: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct RpcStreamingConfig {
pub observe: bool,
pub resilience: bool,
pub timeout: Option<Duration>,
}
impl RpcStreamingConfig {
pub fn production_defaults() -> Self {
Self {
observe: true,
resilience: true,
timeout: Some(Duration::from_secs(30)),
}
}
#[allow(deprecated)]
#[deprecated(note = "use production_defaults instead")]
pub fn go_zero_defaults() -> Self {
Self::production_defaults()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RpcResilienceConfig {
pub breaker_enabled: bool,
pub breaker_failure_threshold: u32,
pub breaker_reset_timeout: Duration,
pub breaker_sre_enabled: bool,
pub breaker_sre_k_millis: u32,
pub breaker_sre_protection: u64,
pub max_concurrency: Option<usize>,
pub request_timeout: Duration,
pub shedding_enabled: bool,
pub shedding_max_in_flight: Option<usize>,
pub shedding_min_request_count: u64,
pub shedding_max_latency: Duration,
pub shedding_cpu_threshold_millis: u32,
pub shedding_cool_off: Duration,
pub shedding_window_buckets: usize,
pub shedding_window_bucket_duration: Duration,
#[cfg(all(feature = "resil", feature = "cache-redis"))]
pub rate_limiter: RpcRateLimiterConfig,
}
impl Default for RpcResilienceConfig {
fn default() -> Self {
Self {
breaker_enabled: false,
breaker_failure_threshold: 5,
breaker_reset_timeout: Duration::from_secs(30),
breaker_sre_enabled: false,
breaker_sre_k_millis: 1500,
breaker_sre_protection: 5,
max_concurrency: None,
request_timeout: Duration::from_secs(5),
shedding_enabled: false,
shedding_max_in_flight: None,
shedding_min_request_count: 20,
shedding_max_latency: Duration::from_millis(250),
shedding_cpu_threshold_millis: 900,
shedding_cool_off: Duration::from_secs(1),
shedding_window_buckets: 50,
shedding_window_bucket_duration: Duration::from_millis(100),
#[cfg(all(feature = "resil", feature = "cache-redis"))]
rate_limiter: RpcRateLimiterConfig::default(),
}
}
}
impl RpcResilienceConfig {
pub fn production_defaults() -> Self {
Self {
breaker_enabled: true,
breaker_sre_enabled: true,
max_concurrency: Some(1024),
request_timeout: Duration::from_secs(5),
shedding_enabled: true,
shedding_max_in_flight: Some(1024),
shedding_min_request_count: 20,
shedding_max_latency: Duration::from_millis(250),
..Self::default()
}
}
#[allow(deprecated)]
#[deprecated(note = "use production_defaults instead")]
pub fn go_zero_defaults() -> Self {
Self::production_defaults()
}
}
#[cfg(all(feature = "resil", feature = "cache-redis"))]
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum RpcRateLimiterConfig {
#[default]
Disabled,
RedisToken(crate::resil::RedisTokenLimiterConfig),
RedisPeriod(crate::resil::RedisPeriodLimiterConfig),
}