Make RateLimit Clone (#794)
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.
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.
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
AtomicRatethat we can clone, then make RateLimit generic over aRateImpltrait and then RateLimit beCloneifSandRateImplareClone.
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)?
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).