redis_rate
Redis-backed rate limiting for Go using the GCRA leaky-bucket algorithm.
Repository Health
Technical Analysis
redis_rate is a Go library that implements distributed rate limiting on top of Redis, using the GCRA (Generic Cell Rate Algorithm, aka leaky bucket) to enforce per-second, per-minute, or custom-period limits across any number of application instances. It ports the widely-used redis-gcra Lua script into a small, dependency-light Go API built directly on go-redis/v9.
Because the algorithm runs as a single atomic Lua script inside Redis, every AllowN or AllowAtMost call is race-free even under concurrent access from multiple processes, making it a common building block for API gateways, per-user quota enforcement, and login-attempt throttling.
What You Get
- A Limiter type built on any go-redis v9 client (single node, cluster, or ring) with no extra infrastructure beyond Redis itself
- PerSecond, PerMinute, and PerHour helpers for defining common limits, plus a raw Limit struct for custom rate/burst/period combinations
- AllowN and AllowAtMost methods for atomic, race-free limit checks backed by a single Lua script executed inside Redis
- A Reset method to clear a key’s rate-limit state on demand, and a Result struct exposing Allowed, Remaining, RetryAfter, and ResetAfter for building 429 responses and Retry-After headers
Common Use Cases
- Rate-limiting API endpoints per user, API key, or IP address across a horizontally-scaled service
- Throttling login attempts to slow down credential-stuffing and brute-force attacks
- Enforcing per-tenant quotas in a multi-tenant SaaS backend
- Smoothing bursty background job or webhook processing against a fixed throughput budget
Under The Hood
Architecture
The library is a single small package (redis_rate) split across two files: rate.go, which defines the public API (Limit, Limiter, Result, and the PerSecond/PerMinute/PerHour constructors), and lua.go, which embeds two Lua scripts (allowN and allowAtMost) implementing the GCRA algorithm atomically inside Redis. Limiter wraps a minimal rediser interface (Eval, EvalSha, ScriptExists, ScriptLoad, Del, plus read-only variants) that any go-redis v9 client already satisfies, so there is no dependency-injection framework, just a narrow interface boundary against go-redis. Data flows from a caller’s Allow/AllowN/AllowAtMost call, through ARGV values (burst, rate, period, cost) passed into the Lua script, to a single atomic Redis key (prefixed rate:), whose reply is parsed back into a Result. The two Lua scripts duplicate their time-computation boilerplate rather than sharing a template, which is the main coupling risk if the underlying algorithm ever needs to change.
Tech Stack
A Go 1.19 module with one runtime dependency, github.com/redis/go-redis/v9 (v9.0.2), used for the Redis client and Lua script execution primitives; stretchr/testify v1.8.1 is a dev-only test dependency. Indirect dependencies are go-redis’s own transitive packages (xxhash, go-rendezvous for consistent hashing, yaml.v3 pulled in by testify). There is no web framework, ORM, or bundler involved — build tooling is a plain Makefile plus Travis CI (.travis.yml) and a renovate.json for automated dependency-update PRs. It ships as an importable library rather than a standalone service.
Code Quality
The only tests are rate_test.go and example_test.go, which use testify’s require package against a live Redis instance (redis.NewRing) rather than mocks, so running the suite needs a real Redis server despite the rediser interface existing. Naming follows standard Go conventions (exported Limiter/Limit/Result, unexported internals), and errors are propagated as (T, error) throughout with none observed being swallowed. Numeric values returned from the Lua script are parsed with strconv and blind type assertions (e.g. values[0].(int64)), which would panic rather than return an error if Redis ever returned an unexpected shape — a fragility point worth noting. CI runs on Travis, and formatting for non-Go files is enforced via a .prettierrc.
API Design
The public surface is intentionally tiny: NewLimiter, Allow/AllowN/AllowAtMost, Reset, and three Limit constructors, so getting started requires little more than constructing a go-redis client. Result exposes exactly the fields an HTTP handler needs (Allowed, Remaining, RetryAfter, ResetAfter) to build a 429 response and Retry-After header without touching Lua or Redis details directly. Distinguishing AllowN (reject if capacity is insufficient) from AllowAtMost (grant a reduced amount) as separate named methods is a nice ergonomic touch few comparable Go rate-limiter packages surface explicitly. Documentation is limited to a single README example with no extended godoc, but the API’s small surface makes that example cover the common path well.
Used by 3 apps in this directory
Convoy
Developer Tools · Devops
Convoy is an open-source, cloud-native webhooks gateway that ingests events over HTTP or straight from Kafka, SQS, Google Pub/Sub, and RabbitMQ, then reliably delivers them to subscriber endpoints with signed payloads, automatic retries, circuit breaking, and JavaScript-based transformations.
Rill
Analytics · Data Engineering
The fastest BI tool for humans and agents — define metrics, models, and dashboards as code and query them instantly on ClickHouse or DuckDB.
Uptrace
Monitoring · Devops
Unified open-source APM that collects OpenTelemetry traces, metrics, and logs into a single self-hosted platform backed by ClickHouse.