Documentation
¶
Overview ¶
Package ratelimit provides rate limiting primitives for gRPC execution pipelines.
Architecture follows ports-and-adapters:
- Limiter is the port (interface) that any backend must satisfy
- TokenBucket is the in-memory adapter (no external dependencies)
- Redis adapter is available via the ratelimit/redislimiter sub-package
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrRateLimited = errors.New("rate limited")
ErrRateLimited indicates a request was rejected due to rate limiting.
Functions ¶
func IsRateLimited ¶
IsRateLimited checks whether err is a rate-limiting rejection.
Types ¶
type Config ¶
type Config struct {
// Rate is the number of requests permitted per Interval.
Rate int
// Interval is the time window for the rate.
// Defaults to 1 second if zero.
Interval time.Duration
// Burst is the maximum number of requests allowed in a single burst.
// Defaults to Rate if zero.
Burst int
}
Config defines the rate limiting parameters.
type Limiter ¶
type Limiter interface {
// Allow checks whether a request identified by key is permitted.
// An empty key applies global rate limiting.
Allow(ctx context.Context, key string) error
// AllowN checks whether n requests for key are permitted.
AllowN(ctx context.Context, key string, n int) error
}
Limiter is the port that all rate limiting backends must implement.
Contract:
- Allow returns nil if the request is permitted
- Allow returns ErrRateLimited if the request is rejected
- Allow MUST be goroutine-safe
- Allow MUST NOT block indefinitely
- Allow MUST respect context cancellation
type RedisClient ¶
type RedisClient interface {
// Eval runs a Lua script on the Redis server.
// keys are the KEYS arguments, args are the ARGV arguments.
// Returns the script result or an error.
Eval(ctx context.Context, script string, keys []string, args ...any) (any, error)
}
RedisClient is the port that any Redis client library must implement to be used as a rate limiting backend.
This is deliberately minimal — it requires only EVALSHA / EVAL functionality, which every Redis client provides.
Compatible with:
- go-redis/redis (v9)
- gomodule/redigo
- mediocregopher/radix
- Any custom implementation
type RedisSlidingWindow ¶
type RedisSlidingWindow struct {
// contains filtered or unexported fields
}
RedisSlidingWindow implements Limiter using a Redis-backed sliding window.
Algorithm:
- Uses a sorted set per key with timestamps as scores
- Removes entries outside the window
- Counts entries within the window
- Adds new entry if under the limit
- All done atomically via Lua script
This provides precise sliding window rate limiting suitable for distributed systems where multiple instances share a Redis cluster.
func NewRedisSlidingWindow ¶
func NewRedisSlidingWindow(client RedisClient, cfg Config, opts ...RedisSlidingWindowOption) *RedisSlidingWindow
NewRedisSlidingWindow creates a Redis-backed sliding window rate limiter.
Example with go-redis:
rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
limiter := ratelimit.NewRedisSlidingWindow(rdb, ratelimit.Config{
Rate: 100,
Interval: time.Second,
})
type RedisSlidingWindowOption ¶
type RedisSlidingWindowOption func(*RedisSlidingWindow)
RedisSlidingWindowOption configures the Redis sliding window limiter.
func WithKeyPrefix ¶
func WithKeyPrefix(prefix string) RedisSlidingWindowOption
WithKeyPrefix sets a prefix for all Redis keys used by this limiter. Default: "grip:rl:"
type TokenBucket ¶
type TokenBucket struct {
// contains filtered or unexported fields
}
TokenBucket implements Limiter using the token bucket algorithm.
Features:
- Per-key rate limiting (each key has its own bucket)
- Global rate limiting (use empty key)
- Thread-safe (sync.Mutex per bucket)
- Lazy bucket creation
- Automatic stale bucket cleanup
func NewTokenBucket ¶
func NewTokenBucket(cfg Config) *TokenBucket
NewTokenBucket creates an in-memory token bucket rate limiter.
Example:
limiter := ratelimit.NewTokenBucket(ratelimit.Config{
Rate: 100, // 100 requests
Interval: time.Second, // per second
Burst: 150, // burst up to 150
})
func (*TokenBucket) Allow ¶
func (tb *TokenBucket) Allow(_ context.Context, key string) error
Allow checks if one request for key is permitted.
func (*TokenBucket) Cleanup ¶
func (tb *TokenBucket) Cleanup(maxAge time.Duration) int
Cleanup removes stale buckets that haven't been used within maxAge.
func (*TokenBucket) Len ¶
func (tb *TokenBucket) Len() int
Len returns the number of active buckets.