ratelimitpg

package module
v0.3.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 23, 2026 License: Apache-2.0 Imports: 15 Imported by: 3

Documentation

Overview

Package ratelimitpg shares rate limits across instances in PostgreSQL (ADR-0052). A Limiter implements ratelimit.Taker with GCRA, the generic cell rate algorithm: each key keeps one row with its theoretical arrival time, and one statement decides and records a request, so every instance sees the same budget with the same rate-and-burst behaviour as the in-memory limiter. Keys are stored hashed.

Two in-memory limiters protect it:

  • a local pre-check with twice the burst refuses a client far over its limit without touching the database, so a flood of requests can't become a flood of writes;
  • a fallback with the same limit decides when the database doesn't answer within DecisionTimeout, and a warning is logged at most once a minute per limiter, so requests keep working with per-instance limits during an outage.

Stability: stable (ADR-0015, ADR-0054).

Index

Constants

View Source
const (
	// DecisionTimeout bounds each database decision.
	DecisionTimeout = 250 * time.Millisecond
)

Variables

View Source
var Migrations fs.FS = mustSub(migrationFiles, "migrations")

Migrations holds the module's goose migrations: the ratelimit_buckets table. Apps copy them into db/migrations; tests can apply them directly with pgtest.

Functions

This section is empty.

Types

type Limiter

type Limiter struct {
	// contains filtered or unexported fields
}

Limiter shares one limit across instances. Limiters with the same name on any instance share their keys' budgets. It is safe for concurrent use.

func (*Limiter) Take

func (l *Limiter) Take(ctx context.Context, key string) (ratelimit.Decision, error)

Take implements ratelimit.Taker. It fails only for an empty key or an invalid limit; database failures are decided in memory.

type Option

type Option func(*Store)

An Option configures a Store.

func WithClock

func WithClock(now func() time.Time) Option

WithClock makes decisions at now instead of the database's time, for tests.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger sets the logger for fallback warnings. Default: discard.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store holds the shared buckets of every limiter. It is safe for concurrent use.

func NewStore

func NewStore(pool *pgxpool.Pool, opts ...Option) (*Store, error)

NewStore returns a store on pool, which must have the module's migrations applied. Decisions count the OpenTelemetry metrics ratelimit.decisions and ratelimit.fallbacks.

func (*Store) DeleteExpired

func (s *Store) DeleteExpired(ctx context.Context, limit int) (int64, error)

DeleteExpired removes up to limit buckets whose keys are back to a full budget, so the table holds only recently limited keys. Apps run it from a periodic job.

func (*Store) Limiter

func (s *Store) Limiter(name string, limit func(context.Context) ratelimit.Limit) (*Limiter, error)

Limiter returns the limiter name, whose limit is read on every decision, so a limit backed by a runtime setting applies at once. The name is part of every key: use one name per kind of limit, such as auth_login.

func (*Store) Reset

func (s *Store) Reset(ctx context.Context, name, key string) (bool, error)

Reset forgets the budget of key under the limiter named name, for operators unblocking a client (ADR-0070). It reports whether a bucket existed. Local and fallback limiters in memory keep their own state, which empties within the window.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL