valkey

package
v0.0.0-...-9204231 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// CheckoutRateLimitWindow is the sliding window duration for checkout rate
	// limiting.
	CheckoutRateLimitWindow = 1 * time.Hour

	// CheckoutRateLimitKeyPrefix is the Valkey key prefix for checkout rate
	// limit counters.
	CheckoutRateLimitKeyPrefix = "domain:ratelimit:checkout:"
)
View Source
const (
	RateLimitKeyPrefix     = "ratelimit:"
	DefaultRateLimit       = 100 // requests per window
	DefaultRateLimitWindow = time.Minute
)
View Source
const (
	// SlidingWindowTTLMultiplier controls how long sorted set entries are
	// retained beyond the window duration. Using 2x ensures entries from the
	// previous window are available for overlap calculation.
	SlidingWindowTTLMultiplier = 2
)

Variables

View Source
var Module = fx.Module("valkey",
	fx.Provide(NewClient),
	fx.Provide(
		fx.Annotate(
			func(client *redis.Client) health.Checker {
				return NewHealthChecker(client)
			},
			fx.ResultTags(`group:"health.checkers"`),
		),
	),
	fx.Provide(func(client *redis.Client, clk clock.Clock) *SlidingWindowRateLimiter {
		return NewSlidingWindowRateLimiter(client, DefaultRateLimit, DefaultRateLimitWindow, clk)
	}),
	fx.Provide(func(inner *SlidingWindowRateLimiter, cfg *config.Config, logger *slog.Logger) *ResilientRateLimiter {
		return NewResilientRateLimiter(inner, cfg.CircuitBreaker.Valkey, logger)
	}),
	fx.Provide(NewDomainRateLimiter),
	fx.Invoke(registerMetrics),
)

Module provides the Valkey client, rate limiters, and Prometheus metrics collector to the Fx dependency graph.

Functions

func NewClient

func NewClient(lc fx.Lifecycle, cfg *config.Config) (*redis.Client, error)

NewClient creates a Valkey (Redis-compatible) client and registers Fx lifecycle hooks for health-checking on start and graceful shutdown on stop.

Types

type DomainRateLimiter

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

DomainRateLimiter implements billing.DomainRateLimiter using Valkey sliding window rate limiters. It reuses the same SlidingWindowRateLimiter implementation used by the HTTP middleware but with domain-specific limits.

func NewDomainRateLimiter

func NewDomainRateLimiter(client *redis.Client, cfg *config.Config, clk clock.Clock) *DomainRateLimiter

NewDomainRateLimiter creates a DomainRateLimiter backed by the given Valkey client. The checkout rate limit threshold is read from cfg; if zero, the platform default is used.

func (*DomainRateLimiter) AllowCheckout

func (r *DomainRateLimiter) AllowCheckout(ctx context.Context, userID string) (bool, error)

AllowCheckout checks if the user is within their checkout rate limit.

type HealthChecker

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

HealthChecker implements health.Checker for the Valkey (Redis-compatible) connection.

func NewHealthChecker

func NewHealthChecker(client *redis.Client) *HealthChecker

NewHealthChecker returns a Valkey health checker that validates connectivity by executing a PING command.

func (*HealthChecker) HealthCheck

func (c *HealthChecker) HealthCheck(ctx context.Context) health.ComponentCheck

HealthCheck pings Valkey and returns the component status.

type InMemoryRateLimiter

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

InMemoryRateLimiter is a simple in-process rate limiter backed by a map with a mutex. It is intended for unit tests where a real Valkey instance is not available.

func NewInMemoryRateLimiter

func NewInMemoryRateLimiter(limit int) *InMemoryRateLimiter

NewInMemoryRateLimiter returns a RateLimiter that tracks counts in memory.

func (*InMemoryRateLimiter) Allow

func (r *InMemoryRateLimiter) Allow(_ context.Context, key string) (bool, error)

Allow increments the counter for key and returns whether it is within the configured limit.

type MetricsCollector

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

MetricsCollector implements prometheus.Collector and reports go-redis connection pool statistics on every Prometheus scrape. This avoids a background goroutine — metrics are fetched lazily when scraped.

func NewMetricsCollector

func NewMetricsCollector(client *redis.Client) *MetricsCollector

NewMetricsCollector returns a collector that exposes go-redis pool stats. It must be registered with prometheus.Register or promauto equivalent.

func (*MetricsCollector) Collect

func (c *MetricsCollector) Collect(ch chan<- prometheus.Metric)

Collect fetches current pool stats from go-redis and sends them as metrics.

func (*MetricsCollector) Describe

func (c *MetricsCollector) Describe(ch chan<- *prometheus.Desc)

Describe sends the metric descriptors to the channel.

type RateLimiter

type RateLimiter interface {
	Allow(ctx context.Context, key string) (bool, error)
}

RateLimiter determines whether a request identified by key should be allowed.

type ResilientRateLimiter

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

ResilientRateLimiter wraps a RateLimiter with a circuit breaker. When the underlying store is unavailable, the breaker opens and Allow() returns (true, nil) immediately (fail-open), avoiding hammering a dead Valkey instance.

func NewResilientRateLimiter

func NewResilientRateLimiter(inner *SlidingWindowRateLimiter, cbCfg circuitbreaker.Config, logger *slog.Logger) *ResilientRateLimiter

NewResilientRateLimiter wraps the provided SlidingWindowRateLimiter with a circuit breaker configured by cbCfg. When the breaker opens, Allow returns (true, nil) to fail-open gracefully.

func (*ResilientRateLimiter) Allow

func (r *ResilientRateLimiter) Allow(ctx context.Context, key string) (bool, error)

Allow checks the rate limit through the circuit breaker. If the breaker is open or the inner limiter returns an error, the request is allowed through (fail-open) and the fallback counter is incremented.

type SlidingWindowRateLimiter

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

SlidingWindowRateLimiter uses Redis sorted sets to implement a sliding window rate limiter. Each request is stored as a member scored by its timestamp. The window slides continuously, preventing the burst-at-boundary problem that fixed-window counters suffer from.

All operations are executed atomically via a Lua script to avoid race conditions between concurrent callers.

func NewSlidingWindowRateLimiter

func NewSlidingWindowRateLimiter(client *redis.Client, limit int, window time.Duration, clk clock.Clock) *SlidingWindowRateLimiter

NewSlidingWindowRateLimiter returns a RateLimiter that uses sorted sets for sliding window rate limiting.

func (*SlidingWindowRateLimiter) Allow

func (r *SlidingWindowRateLimiter) Allow(ctx context.Context, key string) (bool, error)

Allow checks whether the given key is within its rate limit using a sliding window over a Redis sorted set. It atomically removes expired entries, counts current entries, conditionally adds the new request, and sets a TTL — all in a single Lua script execution for true atomicity.

type ValkeyRateLimiter

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

ValkeyRateLimiter uses Redis INCR + EXPIRE pipeline for distributed rate limiting with a fixed-window counter approach.

func NewValkeyRateLimiter

func NewValkeyRateLimiter(client *redis.Client, limit int, window time.Duration) *ValkeyRateLimiter

NewValkeyRateLimiter returns a RateLimiter backed by a Valkey/Redis client.

func (*ValkeyRateLimiter) Allow

func (r *ValkeyRateLimiter) Allow(ctx context.Context, key string) (bool, error)

Allow checks whether the given key is within its rate limit. It atomically increments the counter and sets an expiry on first access within a window.

Jump to

Keyboard shortcuts

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