a2a_protocol_server/
tenant_config.rs1use std::collections::HashMap;
51use std::time::Duration;
52
53#[derive(Debug, Clone, Default, PartialEq, Eq)]
61pub struct TenantLimits {
62 pub max_concurrent_tasks: Option<usize>,
64
65 pub executor_timeout: Option<Duration>,
67
68 pub event_queue_capacity: Option<usize>,
70
71 pub max_stored_tasks: Option<usize>,
73
74 pub rate_limit_rps: Option<u32>,
76}
77
78impl TenantLimits {
79 #[must_use]
81 pub fn builder() -> TenantLimitsBuilder {
82 TenantLimitsBuilder::default()
83 }
84}
85
86#[derive(Debug, Clone, Default)]
90pub struct TenantLimitsBuilder {
91 max_concurrent_tasks: Option<usize>,
92 executor_timeout: Option<Duration>,
93 event_queue_capacity: Option<usize>,
94 max_stored_tasks: Option<usize>,
95 rate_limit_rps: Option<u32>,
96}
97
98impl TenantLimitsBuilder {
99 #[must_use]
101 pub const fn max_concurrent_tasks(mut self, n: usize) -> Self {
102 self.max_concurrent_tasks = Some(n);
103 self
104 }
105
106 #[must_use]
108 pub const fn executor_timeout(mut self, d: Duration) -> Self {
109 self.executor_timeout = Some(d);
110 self
111 }
112
113 #[must_use]
115 pub const fn event_queue_capacity(mut self, n: usize) -> Self {
116 self.event_queue_capacity = Some(n);
117 self
118 }
119
120 #[must_use]
122 pub const fn max_stored_tasks(mut self, n: usize) -> Self {
123 self.max_stored_tasks = Some(n);
124 self
125 }
126
127 #[must_use]
129 pub const fn rate_limit_rps(mut self, rps: u32) -> Self {
130 self.rate_limit_rps = Some(rps);
131 self
132 }
133
134 #[must_use]
136 pub const fn build(self) -> TenantLimits {
137 TenantLimits {
138 max_concurrent_tasks: self.max_concurrent_tasks,
139 executor_timeout: self.executor_timeout,
140 event_queue_capacity: self.event_queue_capacity,
141 max_stored_tasks: self.max_stored_tasks,
142 rate_limit_rps: self.rate_limit_rps,
143 }
144 }
145}
146
147#[derive(Debug, Clone, Default)]
155pub struct PerTenantConfig {
156 pub default: TenantLimits,
158
159 pub overrides: HashMap<String, TenantLimits>,
161}
162
163impl PerTenantConfig {
164 #[must_use]
166 pub fn builder() -> PerTenantConfigBuilder {
167 PerTenantConfigBuilder::default()
168 }
169
170 #[must_use]
175 pub fn get(&self, tenant_id: &str) -> &TenantLimits {
176 self.overrides.get(tenant_id).unwrap_or(&self.default)
177 }
178}
179
180#[derive(Debug, Clone, Default)]
182pub struct PerTenantConfigBuilder {
183 default: TenantLimits,
184 overrides: HashMap<String, TenantLimits>,
185}
186
187impl PerTenantConfigBuilder {
188 #[must_use]
190 pub const fn default_limits(mut self, limits: TenantLimits) -> Self {
191 self.default = limits;
192 self
193 }
194
195 #[must_use]
197 pub fn with_override(mut self, tenant_id: impl Into<String>, limits: TenantLimits) -> Self {
198 self.overrides.insert(tenant_id.into(), limits);
199 self
200 }
201
202 #[must_use]
204 pub fn build(self) -> PerTenantConfig {
205 PerTenantConfig {
206 default: self.default,
207 overrides: self.overrides,
208 }
209 }
210}
211
212#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn default_limits_are_all_none() {
220 let limits = TenantLimits::default();
221 assert_eq!(limits.max_concurrent_tasks, None);
222 assert_eq!(limits.executor_timeout, None);
223 assert_eq!(limits.event_queue_capacity, None);
224 assert_eq!(limits.max_stored_tasks, None);
225 assert_eq!(limits.rate_limit_rps, None);
226 }
227
228 #[test]
229 fn builder_sets_all_fields() {
230 let limits = TenantLimits::builder()
231 .max_concurrent_tasks(10)
232 .executor_timeout(Duration::from_secs(30))
233 .event_queue_capacity(256)
234 .max_stored_tasks(1000)
235 .rate_limit_rps(100)
236 .build();
237
238 assert_eq!(limits.max_concurrent_tasks, Some(10));
239 assert_eq!(limits.executor_timeout, Some(Duration::from_secs(30)));
240 assert_eq!(limits.event_queue_capacity, Some(256));
241 assert_eq!(limits.max_stored_tasks, Some(1000));
242 assert_eq!(limits.rate_limit_rps, Some(100));
243 }
244
245 #[test]
246 fn per_tenant_config_returns_override() {
247 let config = PerTenantConfig::builder()
248 .default_limits(TenantLimits::builder().max_concurrent_tasks(10).build())
249 .with_override(
250 "premium",
251 TenantLimits::builder().max_concurrent_tasks(1000).build(),
252 )
253 .build();
254
255 assert_eq!(config.get("premium").max_concurrent_tasks, Some(1000));
256 }
257
258 #[test]
259 fn per_tenant_config_falls_back_to_default() {
260 let config = PerTenantConfig::builder()
261 .default_limits(TenantLimits::builder().rate_limit_rps(50).build())
262 .build();
263
264 assert_eq!(config.get("unknown-tenant").rate_limit_rps, Some(50));
265 }
266
267 #[test]
268 fn per_tenant_config_default_is_empty() {
269 let config = PerTenantConfig::default();
270 let limits = config.get("any");
271 assert_eq!(*limits, TenantLimits::default());
272 }
273
274 #[test]
275 fn multiple_overrides() {
276 let config = PerTenantConfig::builder()
277 .default_limits(TenantLimits::default())
278 .with_override("a", TenantLimits::builder().rate_limit_rps(10).build())
279 .with_override("b", TenantLimits::builder().rate_limit_rps(20).build())
280 .build();
281
282 assert_eq!(config.get("a").rate_limit_rps, Some(10));
283 assert_eq!(config.get("b").rate_limit_rps, Some(20));
284 assert_eq!(config.get("c").rate_limit_rps, None);
285 }
286
287 #[test]
288 fn tenant_limits_builder_returns_functional_builder() {
289 let limits = TenantLimits::builder().max_concurrent_tasks(42).build();
291 assert_eq!(limits.max_concurrent_tasks, Some(42));
292 }
293
294 #[test]
295 fn per_tenant_config_builder_returns_functional_builder() {
296 let config = PerTenantConfig::builder()
298 .default_limits(TenantLimits::builder().rate_limit_rps(99).build())
299 .build();
300 assert_eq!(config.get("any").rate_limit_rps, Some(99));
301 }
302}