Skip to main content

fraiseql_server/config/
rate_limiting.rs

1//! Rate limiting configuration with backpressure support.
2
3use serde::Deserialize;
4
5/// Rate-limiting configuration applied to HTTP endpoints.
6#[derive(Debug, Clone, Deserialize)]
7pub struct RateLimitingConfig {
8    /// Whether rate limiting is active.  Default: `true`.
9    #[serde(default = "default_enabled")]
10    pub enabled: bool,
11
12    /// Default rate limit (e.g., "100/minute")
13    pub default: String,
14
15    /// Storage backend: memory, redis
16    #[serde(default = "default_backend")]
17    pub backend: String,
18
19    /// Redis URL (if using redis storage)
20    pub redis_url_env: Option<String>,
21
22    /// Custom rules
23    #[serde(default)]
24    pub rules: Vec<RateLimitRule>,
25
26    /// Backpressure configuration
27    #[serde(default)]
28    pub backpressure: BackpressureConfig,
29}
30
31const fn default_enabled() -> bool {
32    true
33}
34fn default_backend() -> String {
35    "memory".to_string()
36}
37
38/// A single rate-limit rule applied to a path, mutation, or query pattern.
39#[derive(Debug, Clone, Deserialize)]
40pub struct RateLimitRule {
41    /// Match by path pattern (e.g., "/auth/*")
42    pub path: Option<String>,
43
44    /// Match by mutation name
45    pub mutation: Option<String>,
46
47    /// Match by query name
48    pub query: Option<String>,
49
50    /// Limit (e.g., "10/minute", "100/hour")
51    pub limit: String,
52
53    /// Key extraction: ip, user, `api_key`, composite
54    #[serde(default = "default_key_by")]
55    pub by: String,
56
57    /// Burst allowance (requests above limit that can be queued)
58    #[serde(default)]
59    pub burst: Option<u32>,
60}
61
62fn default_key_by() -> String {
63    "ip".to_string()
64}
65
66/// Backpressure settings that control request queuing and load shedding.
67#[derive(Debug, Clone, Deserialize)]
68pub struct BackpressureConfig {
69    /// Enable request queuing when at limit
70    #[serde(default)]
71    pub queue_enabled: bool,
72
73    /// Maximum queue size per key
74    #[serde(default = "default_queue_size")]
75    pub max_queue_size: usize,
76
77    /// Maximum time to wait in queue
78    #[serde(default = "default_queue_timeout")]
79    pub queue_timeout: String,
80
81    /// Shed load when queue is full (503 vs queue)
82    #[serde(default = "default_load_shed")]
83    pub load_shed: bool,
84}
85
86impl Default for BackpressureConfig {
87    fn default() -> Self {
88        Self {
89            queue_enabled:  false,
90            max_queue_size: default_queue_size(),
91            queue_timeout:  default_queue_timeout(),
92            load_shed:      default_load_shed(),
93        }
94    }
95}
96
97const fn default_queue_size() -> usize {
98    100
99}
100fn default_queue_timeout() -> String {
101    "5s".to_string()
102}
103const fn default_load_shed() -> bool {
104    true
105}