Documentation
¶
Overview ¶
Package ratelimit limits requests per key (token, user, IP). Memory uses GCRA, a smooth token bucket that needs one timestamp per key, and fits one process; Window counts fixed windows in a shared store (the database cache, so several servers on one SQL database share budgets); drivers/redis provides a shared GCRA limiter.
Middleware applies a Limiter to a route, keyed by a KeyFunc such as ByIP or ByToken; it sets the RateLimit-* headers, answers 429 with Retry-After and denies when the limiter fails. Apps build limiters with app.RateLimiters(), configured by RATE_LIMIT_STORE.
See https://github.com/AlexGalhardo/vukem/blob/main/docs/subsystems.md.
Example ¶
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"time"
"github.com/AlexGalhardo/vukem/ratelimit"
)
func main() {
limiter := ratelimit.NewMemory(2, time.Minute)
h := ratelimit.Middleware(limiter, ratelimit.ByIP)(
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
}),
)
for range 3 {
req := httptest.NewRequest(http.MethodGet, "/api/posts", http.NoBody)
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
fmt.Println(rec.Code, rec.Header().Get("RateLimit-Remaining"))
}
}
Output: 204 1 204 0 429 0
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ByToken ¶
ByToken keys requests by bearer token (hashed, never stored in clear), falling back to the client IP. Use it after authentication (auth.Required), behind an IP limit: before the token is verified, a client rotating made-up tokens gets a fresh bucket on every request.
func Middleware ¶
Middleware limits requests with l, keyed by key (ByIP when nil). It sets RateLimit-Limit/Remaining/Reset on every response and answers 429 with Retry-After when the bucket is empty. A failing limiter denies the request (fail closed).
Types ¶
type Counter ¶ added in v0.23.0
type Counter interface {
Increment(ctx context.Context, key string, delta int64, ttl time.Duration) (int64, error)
}
Counter is the store a Window counts in: a cache.Store (database, Redis), a *cache.Cache (adds its key prefix) or anything whose Increment is atomic across the servers sharing it.
type Factory ¶ added in v0.23.0
Factory builds a limiter of limit requests per window; name separates the budgets of limiters sharing one store ("login", "api").
type Memory ¶
type Memory struct {
// contains filtered or unexported fields
}
Memory is an in-process GCRA limiter: limit requests per window, with bursts up to limit.
type Result ¶
type Result struct {
Allowed bool
Limit int
Remaining int
ResetAfter time.Duration // until the bucket is full again
RetryAfter time.Duration // when denied: until the next request is allowed
}
Result is the outcome of one Allow call.
type Window ¶ added in v0.23.0
type Window struct {
// contains filtered or unexported fields
}
Window is a fixed-window limiter over a shared Counter: every server using the same store shares one budget per key. Windows are aligned to the clock, so a client can send up to 2×limit around a window boundary (limit at the end of one, limit at the start of the next); use Memory or the Redis GCRA limiter when bursts must stay within limit.
func NewWindow ¶ added in v0.23.0
NewWindow allows limit requests per window for each key, counted in c under "ratelimit:<name>:<SHA-256 of key>:<window start>". name is 1-64 letters, digits, '.', '_' or '-'; with any other name every Allow fails, so the route denies (503) instead of sharing budgets.