GCRA for Ruby
gcra is a Ruby implementation of a generic cell rate algorithm (GCRA), ported from the Go implementation throttled. It's useful for rate limiting (e.g. for HTTP requests) and allows weights specified per request.
gcra currently uses Redis (>= 2.6 for EVAL, PEXPIRE, and PSETEX) as a data store, although it supports other store implementations.
Add to your
gem 'gcra' gem 'redis'
Create Redis, RedisStore and RateLimiter instances:
require 'redis' require 'gcra/rate_limiter' require 'gcra/redis_store' redis = Redis.new(host: 'localhost', port: 6379, timeout: 0.1) key_prefix = 'rate-limit-app1:' store = ::.(redis, key_prefix) rate_period = 0.5 # Two requests per second max_burst = 10 # Allow 10 additional requests as a burst limiter = ::.(store, rate_period, max_burst)
rate_period: Period between two requests, allowed as a sustained rate. Example: 0.1 for 10 requests per second
max_burst: Number of requests allowed as a burst in addition to the sustained rate. If the burst is used up, one additional request allowed as burst 'comes back' after each
rate_periodwhere no request was made.
Rate limit a request (call this before each request):
key = '123' # e.g. an account identifier quantity = 1 # the number of requests 'used up' by this request, useful e.g. for batch requests exceeded, info = limiter.limit(key, quantity) # => [false, #<struct GCRA::RateLimitInfo limit=11, remaining=10, reset_after=0.5, retry_after=nil>]
falsemeans the request should be allowed,
truemeans the request would exceed the limit and should be blocked.
GCRA::RateLimitInfocontains information that might be useful for your API users. It's a
Structwith the following fields:
limit: Contains the number of requests that can be made if no previous requests have been made (or they were long enough ago). That's
max_burstplus one. The latter is necessary so requests are allowed at all when
max_burstis set to zero.
remaining: The number of remaining requests that can be made immediately, i.e. the remaining burst.
reset_after: The time in seconds until the full burst will be available again.
retry_after: Set to
nilif a request is allowed or it otherwise doesn't make sense to retry a request (if
quantityis larger than
max_burst). For a blocked request that can be retried later, set to the duration in seconds until the next request with the given quantity will be allowed.
RateLimiter#limit only tells you whether to limit a request or not. You'll have to react to its response yourself and e.g. return an error message and stop processing a request if the limit was exceeded.