Skip to content

Ability to control RateLimiter start time #252

@jonasmalacofilho

Description

@jonasmalacofilho

Hi Andreas,

I've been working on a distributed rate limiter based on governor. GCRA is particularly well suited for this, I think, since the only state that needs to be stored is the TAT.

I've implemented a StateStore backed by Redis/ValKey, where the CAS loop uses a simple WATCH/MULTI/EXEC transaction pattern. Of course, the same quota settings, underlying state store and a common (wall or otherwise) clock must be used by all nodes for this to work correctly.

Additionally, one issue I found is that a governor RateLimiter records the TATs relative to the time it was created (according to the specified clock), and there's no good way to influence this. This is a problem because, in the distributed rate limiter scenario, multiple RateLimiters (started at different times) need to agree on the meaning of any TAT retrieved from or stored to the backing store.

The workaround for this I'm using is to implement a clock that lies on the first invocation to now(), but it's a fragile hack and I would like to add some first-party support for this use case to governor.

The simplest alternative would be to add a new associated function to RateLimiter that allows the caller to specify the start time. Alternatively, a new epoch() method could be added to the Clock trait, or to a new trait that has the former as supertrait.

Ideally, though, it would be nice to have some way to tie a state store that depends on shareable clocks with the clock type used in the rate limiter. But it's not immediately obvious to me how this could be done without breaking changes.

Would any of above alternatives be acceptable additions to governor? And/or do you have any other thoughts on this?


By the way, the clock I'm using is based on SystemClock. Assuming NTP has been configured on the host, its precision is sufficient for the applications I have in mind for these distributed rate limiters, which all involve rate limiting attempts per user at certain sensitive auth operations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions