tower icon indicating copy to clipboard operation
tower copied to clipboard

Make RateLimit Clone (#794)

Open sp1ff opened this issue 7 months ago • 2 comments

This (small) patch changes RateLimit to wrap an inner implementation in a Mutex allowing us to clone the type as much as we want without allowing callers to circumvent rate-limiting.

This is the fix to which I alluded in #794.

sp1ff avatar Jul 12 '25 02:07 sp1ff

I don't think users should pay for a mutex if it's not necessary. Maybe we could introduce an AtomicRate that we can clone, then make RateLimit generic over a RateImpl trait and then RateLimit be Clone if S and RateImpl are Clone.

guilload avatar Aug 04 '25 14:08 guilload

Well, I just realized that my solution has a nasty bug: my newly Clonable RateLimit instances will share a reference to one instance of RateLimitInner, which when polled will park the caller's Waker with it's Sleep future (when it's decided to rate-limit). So if more than one RateLimit instance calls ready() when rate-limited, the last one "wins", overwriting the other's Waker, leaving the task stranded.

I don't think users should pay for a mutex if it's not necessary. Maybe we could introduce an AtomicRate that we can clone, then make RateLimit generic over a RateImpl trait and then RateLimit be Clone if S and RateImpl are Clone.

That's interesting: would your RateImpl trait be implemented by various rate limiting strategies (fixed window, sliding window log, sliding window counter, token bucket, &c, &c)?

sp1ff avatar Aug 27 '25 01:08 sp1ff

I'm going to close this PR, since I've gone in a different direction for my particular problem. I've written my own crate, based on the GCRA algorithm, that is both Clone and provides for per-key quotas (e.g. one could rate-limit different API keys at different rates).

sp1ff avatar Jan 07 '26 18:01 sp1ff