diff --git a/src/net/RateLimiter.zig b/src/net/RateLimiter.zig index a9b55c2..cf17e15 100644 --- a/src/net/RateLimiter.zig +++ b/src/net/RateLimiter.zig @@ -29,9 +29,12 @@ pub fn init(max_per_window: u32, window_ns: u64) RateLimiter { }; } -/// Convenience: N requests per minute +/// Convenience: N requests per minute. +/// Starts with 1 token (no burst) to stay within provider sliding-window limits. pub fn perMinute(n: u32) RateLimiter { - return init(n, std.time.ns_per_min); + var rl = init(n, std.time.ns_per_min); + rl.tokens = 1.0; + return rl; } /// Convenience: N requests per day @@ -87,8 +90,19 @@ fn refill(self: *RateLimiter) void { test "rate limiter basic" { var rl = RateLimiter.perMinute(60); - // Should have full bucket initially + // perMinute starts with 1 token (no burst) try std.testing.expect(rl.tryAcquire()); + // Second call should be rate-limited immediately + try std.testing.expect(!rl.tryAcquire()); +} + +test "rate limiter perDay keeps full burst" { + var rl = RateLimiter.perDay(25); + // perDay starts with full bucket + for (0..25) |_| { + try std.testing.expect(rl.tryAcquire()); + } + try std.testing.expect(!rl.tryAcquire()); } test "rate limiter exhaustion" {