a2a_protocol_server/
tenant_config.rs1use std::collections::HashMap;
38use std::time::Duration;
39
40#[derive(Debug, Clone, Default, PartialEq, Eq)]
48pub struct TenantLimits {
49 pub max_concurrent_tasks: Option<usize>,
51
52 pub executor_timeout: Option<Duration>,
54
55 pub event_queue_capacity: Option<usize>,
57
58 pub max_stored_tasks: Option<usize>,
60
61 pub rate_limit_rps: Option<u32>,
63}
64
65impl TenantLimits {
66 #[must_use]
68 pub fn builder() -> TenantLimitsBuilder {
69 TenantLimitsBuilder::default()
70 }
71}
72
73#[derive(Debug, Clone, Default)]
77pub struct TenantLimitsBuilder {
78 max_concurrent_tasks: Option<usize>,
79 executor_timeout: Option<Duration>,
80 event_queue_capacity: Option<usize>,
81 max_stored_tasks: Option<usize>,
82 rate_limit_rps: Option<u32>,
83}
84
85impl TenantLimitsBuilder {
86 #[must_use]
88 pub const fn max_concurrent_tasks(mut self, n: usize) -> Self {
89 self.max_concurrent_tasks = Some(n);
90 self
91 }
92
93 #[must_use]
95 pub const fn executor_timeout(mut self, d: Duration) -> Self {
96 self.executor_timeout = Some(d);
97 self
98 }
99
100 #[must_use]
102 pub const fn event_queue_capacity(mut self, n: usize) -> Self {
103 self.event_queue_capacity = Some(n);
104 self
105 }
106
107 #[must_use]
109 pub const fn max_stored_tasks(mut self, n: usize) -> Self {
110 self.max_stored_tasks = Some(n);
111 self
112 }
113
114 #[must_use]
116 pub const fn rate_limit_rps(mut self, rps: u32) -> Self {
117 self.rate_limit_rps = Some(rps);
118 self
119 }
120
121 #[must_use]
123 pub const fn build(self) -> TenantLimits {
124 TenantLimits {
125 max_concurrent_tasks: self.max_concurrent_tasks,
126 executor_timeout: self.executor_timeout,
127 event_queue_capacity: self.event_queue_capacity,
128 max_stored_tasks: self.max_stored_tasks,
129 rate_limit_rps: self.rate_limit_rps,
130 }
131 }
132}
133
134#[derive(Debug, Clone, Default)]
142pub struct PerTenantConfig {
143 pub default: TenantLimits,
145
146 pub overrides: HashMap<String, TenantLimits>,
148}
149
150impl PerTenantConfig {
151 #[must_use]
153 pub fn builder() -> PerTenantConfigBuilder {
154 PerTenantConfigBuilder::default()
155 }
156
157 #[must_use]
162 pub fn get(&self, tenant_id: &str) -> &TenantLimits {
163 self.overrides.get(tenant_id).unwrap_or(&self.default)
164 }
165}
166
167#[derive(Debug, Clone, Default)]
169pub struct PerTenantConfigBuilder {
170 default: TenantLimits,
171 overrides: HashMap<String, TenantLimits>,
172}
173
174impl PerTenantConfigBuilder {
175 #[must_use]
177 pub const fn default_limits(mut self, limits: TenantLimits) -> Self {
178 self.default = limits;
179 self
180 }
181
182 #[must_use]
184 pub fn with_override(mut self, tenant_id: impl Into<String>, limits: TenantLimits) -> Self {
185 self.overrides.insert(tenant_id.into(), limits);
186 self
187 }
188
189 #[must_use]
191 pub fn build(self) -> PerTenantConfig {
192 PerTenantConfig {
193 default: self.default,
194 overrides: self.overrides,
195 }
196 }
197}
198
199#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn default_limits_are_all_none() {
207 let limits = TenantLimits::default();
208 assert_eq!(limits.max_concurrent_tasks, None);
209 assert_eq!(limits.executor_timeout, None);
210 assert_eq!(limits.event_queue_capacity, None);
211 assert_eq!(limits.max_stored_tasks, None);
212 assert_eq!(limits.rate_limit_rps, None);
213 }
214
215 #[test]
216 fn builder_sets_all_fields() {
217 let limits = TenantLimits::builder()
218 .max_concurrent_tasks(10)
219 .executor_timeout(Duration::from_secs(30))
220 .event_queue_capacity(256)
221 .max_stored_tasks(1000)
222 .rate_limit_rps(100)
223 .build();
224
225 assert_eq!(limits.max_concurrent_tasks, Some(10));
226 assert_eq!(limits.executor_timeout, Some(Duration::from_secs(30)));
227 assert_eq!(limits.event_queue_capacity, Some(256));
228 assert_eq!(limits.max_stored_tasks, Some(1000));
229 assert_eq!(limits.rate_limit_rps, Some(100));
230 }
231
232 #[test]
233 fn per_tenant_config_returns_override() {
234 let config = PerTenantConfig::builder()
235 .default_limits(TenantLimits::builder().max_concurrent_tasks(10).build())
236 .with_override(
237 "premium",
238 TenantLimits::builder().max_concurrent_tasks(1000).build(),
239 )
240 .build();
241
242 assert_eq!(config.get("premium").max_concurrent_tasks, Some(1000));
243 }
244
245 #[test]
246 fn per_tenant_config_falls_back_to_default() {
247 let config = PerTenantConfig::builder()
248 .default_limits(TenantLimits::builder().rate_limit_rps(50).build())
249 .build();
250
251 assert_eq!(config.get("unknown-tenant").rate_limit_rps, Some(50));
252 }
253
254 #[test]
255 fn per_tenant_config_default_is_empty() {
256 let config = PerTenantConfig::default();
257 let limits = config.get("any");
258 assert_eq!(*limits, TenantLimits::default());
259 }
260
261 #[test]
262 fn multiple_overrides() {
263 let config = PerTenantConfig::builder()
264 .default_limits(TenantLimits::default())
265 .with_override("a", TenantLimits::builder().rate_limit_rps(10).build())
266 .with_override("b", TenantLimits::builder().rate_limit_rps(20).build())
267 .build();
268
269 assert_eq!(config.get("a").rate_limit_rps, Some(10));
270 assert_eq!(config.get("b").rate_limit_rps, Some(20));
271 assert_eq!(config.get("c").rate_limit_rps, None);
272 }
273
274 #[test]
275 fn tenant_limits_builder_returns_functional_builder() {
276 let limits = TenantLimits::builder().max_concurrent_tasks(42).build();
278 assert_eq!(limits.max_concurrent_tasks, Some(42));
279 }
280
281 #[test]
282 fn per_tenant_config_builder_returns_functional_builder() {
283 let config = PerTenantConfig::builder()
285 .default_limits(TenantLimits::builder().rate_limit_rps(99).build())
286 .build();
287 assert_eq!(config.get("any").rate_limit_rps, Some(99));
288 }
289}