Documentation
¶
Overview ¶
Package cf_http_ratelimiter is the Caerus Framework HTTP rate limiter component. It is an HTTP-plane helper: apps use it from middleware and handlers to count attempts ("this client / email / action has tried too many times") in a shared store and answer allow/deny plus "try again in N seconds". It is not a second HTTP server and it is not a router (no Echo/Gin/chi dependency).
The same counter API is useful outside middleware too — e.g. a background worker calling Allow / Wait before bursts of outbound REST calls (see Wait).
Index ¶
- Constants
- Variables
- func HashKey(secret, part string) (string, error)
- func Middleware(cfg MiddlewareConfig) (func(http.Handler) http.Handler, error)
- func RemoteAddrKey(r *http.Request) string
- type Config
- type KeyHasher
- type MapFullPolicy
- type MemoryFallbackConfig
- type MiddlewareConfig
- type MissingTTLPolicy
- type Option
- func WithConfig(cfg Config) Option
- func WithConfigSource(name, path string, opts ...SourceOption) Option
- func WithForceMemory(enabled bool) Option
- func WithKeyPrefix(prefix string) Option
- func WithLogger(logger *slog.Logger) Option
- func WithMaxKeyLength(n int) Option
- func WithMemoryMapFullPolicy(policy string) Option
- func WithMemoryMaxEntries(n int) Option
- func WithMetricsEnabled(enabled bool) Option
- func WithName(name string) Option
- func WithUseMemoryFallback(enabled bool) Option
- func WithValkeyName(name string) Option
- func WithWaitDelayFunc(fn WaitDelayFunc) Option
- func WithWaitJitterMax(d time.Duration) Option
- func WithWaitMissingTTLPolicy(policy string) Option
- func WithoutValkeyPeer() Option
- type RateLimiter
- func (c *RateLimiter) Allow(ctx context.Context, key string, limit int64, window time.Duration) (Result, error)
- func (c *RateLimiter) AllowWithPolicy(ctx context.Context, key string, limit int64, window time.Duration, ...) (Result, error)
- func (c *RateLimiter) AllowWithPolicyOpts(ctx context.Context, key string, limit int64, window time.Duration, ...) (Result, error)
- func (c *RateLimiter) ForceMemory() bool
- func (c *RateLimiter) GetDependencies() []string
- func (c *RateLimiter) GetInitOrderStage() cf.Stage
- func (c *RateLimiter) HashIPKeys() bool
- func (c *RateLimiter) Health(ctx context.Context) error
- func (c *RateLimiter) Init(ctx context.Context, fw *cf.CaerusFramework) error
- func (c *RateLimiter) Key(logical string) string
- func (c *RateLimiter) Metrics() []cf_observability.Metric
- func (c *RateLimiter) Name() string
- func (c *RateLimiter) OnConfigReload(source string, cfg any)
- func (c *RateLimiter) Peek(ctx context.Context, key string) (Result, error)
- func (c *RateLimiter) RegisterConfigSources(conf any) error
- func (c *RateLimiter) Reset(ctx context.Context, key string) error
- func (c *RateLimiter) Shutdown(ctx context.Context) error
- func (c *RateLimiter) UseMemoryFallback() bool
- func (c *RateLimiter) Wait(ctx context.Context, key string, limit int64, window time.Duration) error
- func (c *RateLimiter) WaitOpts(ctx context.Context, key string, limit int64, window time.Duration, ...) error
- type Result
- type SourceOption
- type StorageErrorPolicy
- type WaitDelayFunc
- type WaitOptions
Constants ¶
const ( // ComponentName is the framework component name for the http-ratelimiter // component. It is the identifier other components use in GetDependencies // to require it, and it also matches the default configuration source name // so files, env prefixes and flags line up ("http-ratelimiter", // config/http-ratelimiter.json, HTTP_RATELIMITER_, --http-ratelimiter). ComponentName = "http-ratelimiter" // ComponentStage is the stage data-layer components initialize in. ComponentStage = cf.Stage("data") )
Variables ¶
var ErrMemoryFallbackDisabled = errors.New("cf_http_ratelimiter: StorageMemoryFallback requires use_memory_fallback=true")
ErrMemoryFallbackDisabled is returned when a call site asks for StorageMemoryFallback but the component's use_memory_fallback capability is off.
var ErrMissingTTL = errors.New("cf_http_ratelimiter: counter missing TTL")
ErrMissingTTL is returned when a Valkey counter exists with count > 0 but no usable TTL (PTTL <= 0), after the key was scrubbed, and wait_missing_ttl_policy (or a WaitOptions override) is "error".
Functions ¶
func Middleware ¶
Middleware builds a stdlib middleware (func(http.Handler) http.Handler) from cfg. It errors when Limiter, KeyFunc, or OnStoreError are nil, or when Window <= 0. OnStoreError is required: choosing this module means tuning store-error policy — there is no silent FailOpen. StorageMemoryFallback requires the limiter's use_memory_fallback capability to be on. MiddlewareConfig.Memory is wired into AllowWithPolicyOpts for per-route sizing overrides.
The middleware never sleeps. On denial it answers immediately: 429 with a Retry-After header from Result.ResetIn (or 503 for a FailClosed store error, with Retry-After: 1). The client is responsible for waiting.
func RemoteAddrKey ¶
RemoteAddrKey returns the host (IP) from r.RemoteAddr with the port stripped. It is a footnote helper for local demos only — behind a load balancer use identity your ingress/mesh already normalized (e.g. Echo RealIP() under a correct proxy contract), not a client-supplied X-Forwarded-For.
Types ¶
type Config ¶
type Config struct {
// KeyPrefix is an extra logical prefix under the valkey peer's Key().
// Example: peer prefix "auth:" + module prefix "rl" → auth:rl:<key>.
// Default "rl".
KeyPrefix string `json:"key_prefix,omitempty" yaml:"key_prefix,omitempty" env:"KEY_PREFIX"`
// MetricsEnabled — pointer so "omitted" (default on) and an explicit false
// are distinct. When false, Metrics() returns nil.
MetricsEnabled *bool `json:"metrics_enabled,omitempty" yaml:"metrics_enabled,omitempty" env:"METRICS_ENABLED"`
// UseMemoryFallback enables the sticky-note (in-process map) engine. Off → never
// count in-process (MemoryFallback is illegal). Required true when the
// process omits a valkey peer (WithoutValkeyPeer).
UseMemoryFallback *bool `json:"use_memory_fallback,omitempty" yaml:"use_memory_fallback,omitempty" env:"USE_MEMORY_FALLBACK"`
// ForceMemory is break-glass: use sticky notes even when Valkey is missing
// a live client at Init, and prefer the memory path at runtime while set.
// Pair with DegradedMode on the valkey component when Valkey is wired but
// may be down at start. When both ForceMemory and UseMemoryFallback are on and
// Valkey is healthy, lame_memory_mode screams.
ForceMemory *bool `json:"force_memory,omitempty" yaml:"force_memory,omitempty" env:"FORCE_MEMORY"`
// MemoryMaxEntries caps distinct keys in the in-process map. Default 10000.
MemoryMaxEntries int `json:"memory_max_entries,omitempty" yaml:"memory_max_entries,omitempty" env:"MEMORY_MAX_ENTRIES"`
// MemoryFallbackLimit is the optional coarser limit used when a call site
// chooses StorageMemoryFallback. 0 → the call's own limit.
MemoryFallbackLimit int64 `json:"memory_fallback_limit,omitempty" yaml:"memory_fallback_limit,omitempty" env:"MEMORY_FALLBACK_LIMIT"`
// MemoryFallbackWindowSec is the optional coarser window (seconds) used
// when a call site chooses StorageMemoryFallback. 0 → the call's own window.
MemoryFallbackWindowSec float64 `json:"memory_fallback_window_sec,omitempty" yaml:"memory_fallback_window_sec,omitempty" env:"MEMORY_FALLBACK_WINDOW_SEC"`
// MemoryMapFullPolicy must be "allow" or "deny" whenever use_memory_fallback or
// force_memory is true (Init/reload fails otherwise). When both are false
// the field may be empty (map unused).
MemoryMapFullPolicy string `json:"memory_map_full_policy,omitempty" yaml:"memory_map_full_policy,omitempty" env:"MEMORY_MAP_FULL_POLICY"`
// WaitMissingTTLPolicy must be "proceed" or "error" at Init. After scrubbing
// a counter with count > 0 and no TTL: proceed continues (Allow once /
// empty Peek); error returns ErrMissingTTL.
WaitMissingTTLPolicy string `json:"wait_missing_ttl_policy,omitempty" yaml:"wait_missing_ttl_policy,omitempty" env:"WAIT_MISSING_TTL_POLICY"`
// HashIPKeys is a documented toggle for apps: when true, apps should HMAC
// IPs in their KeyFunc (the KeyHasher helper is provided). The component
// exposes it via HashIPKeys(); it does not rewrite keys itself, because the
// HMAC secret is app-owned. Emails/account ids are always hashed by
// convention in the recipes.
HashIPKeys *bool `json:"hash_ip_keys,omitempty" yaml:"hash_ip_keys,omitempty" env:"HASH_IP_KEYS"`
// MaxKeyLength is the maximum byte length of the logical key (default 256).
// 0 after load means "use the default", not unlimited — use the option or
// config explicitly for a higher cap.
MaxKeyLength int `json:"max_key_length,omitempty" yaml:"max_key_length,omitempty" env:"MAX_KEY_LENGTH"`
// WaitJitterMaxSec caps the random extra sleep Wait adds to ResetIn.
// 0 disables jitter. Omitted → the built-in default (~10% of ResetIn capped
// at 1s).
WaitJitterMaxSec *float64 `json:"wait_jitter_max_sec,omitempty" yaml:"wait_jitter_max_sec,omitempty" env:"WAIT_JITTER_MAX_SEC"`
}
Config is the file/env-drivable module configuration. It holds module settings (key prefix, metrics, memory sizing, max key length, wait jitter) — not the per-call limits and windows, which stay caller-supplied (auth / gh-app keep their own policy on their own config sources).
type KeyHasher ¶
type KeyHasher struct {
// contains filtered or unexported fields
}
KeyHasher hashes PII-ish key parts (emails, optionally IPs) before they become rate-limit keys. Emails/account ids are always hashed in the recipes; IPs are hashed when the app enables hash_ip_keys. The secret is app-owned (a pepper or a dedicated rate_limit_key_secret) and must never be logged or stored next to pre-hash identities.
func NewKeyHasher ¶
NewKeyHasher creates a KeyHasher with the given secret. An empty secret is an error: hashing with no secret is effectively a plain SHA-256 and defeats the purpose.
type MapFullPolicy ¶
type MapFullPolicy int
MapFullPolicy is the "fallback/memory map hit its max distinct keys" policy. On MemoryFallbackConfig, the zero value (MapFullAllow) means "inherit the component's required memory_map_full_policy". After resolve, MapFullAllow allows the call without counting and MapFullDeny rejects it.
const ( // MapFullAllow allows a new key without counting when the map is full. // On MemoryFallbackConfig, the zero value also means "inherit component". MapFullAllow MapFullPolicy = iota // MapFullDeny rejects Allow for a new key when the cap is reached. MapFullDeny )
type MemoryFallbackConfig ¶
type MemoryFallbackConfig struct {
// MaxEntries is a hard cap on distinct keys. 0 uses the component's
// configured memory_max_entries.
MaxEntries int
// WhenMapFull is the policy when a new key would exceed MaxEntries.
// MapFullAllow (zero value) uses the component's configured
// memory_map_full_policy; MapFullDeny always denies.
WhenMapFull MapFullPolicy
// Limit is an optional coarser ceiling when running on fallback only.
// 0 uses the call's limit (or the component's memory_fallback_limit).
Limit int64
// Window is an optional coarser window when running on fallback only.
// 0 uses the call's window (or the component's memory_fallback_window_sec).
Window time.Duration
}
MemoryFallbackConfig sizes the in-process memory limiter used by the StorageMemoryFallback policy and by force_memory / memory-only mode. Zero fields fall back to the component's configured values; when those are also zero, the call's own limit/window are used.
type MiddlewareConfig ¶
type MiddlewareConfig struct {
// Limiter is the component instance. Required.
Limiter *RateLimiter
// Limit is the number of calls allowed per Window for each key. <= 0
// disables rate limiting for this middleware (every call allowed).
Limit int64
// Window is the fixed window duration. Must be > 0.
Window time.Duration
// KeyFunc extracts the logical key from the request (e.g. a trusted IP,
// "ip:"+ip). Required — do not invent a clever X-Forwarded-For parser
// here; use identity your ingress/mesh already normalized.
KeyFunc func(*http.Request) string
// OnStoreError is the storage-error policy. Required.
OnStoreError *StorageErrorPolicy
// Memory sizes the memory fallback when OnStoreError == StorageMemoryFallback.
// Wired into AllowWithPolicyOpts so per-route overrides apply.
Memory MemoryFallbackConfig
// OnDenied, when set, is called instead of the default 429/503 response.
// status is http.StatusTooManyRequests for an over-limit denial, or
// http.StatusServiceUnavailable for a FailClosed store error. Use it for
// custom bodies, status codes, or logging.
OnDenied func(w http.ResponseWriter, r *http.Request, res Result, status int)
}
MiddlewareConfig configures the stdlib Middleware. OnStoreError is required (use a pointer so zero does not silently mean FailOpen); Middleware errors when it is nil — choosing this module means tuning store-error policy.
type MissingTTLPolicy ¶
type MissingTTLPolicy int
MissingTTLPolicy selects what happens after scrubbing a counter that has count > 0 but no usable TTL. It must be set explicitly on the component (wait_missing_ttl_policy); WaitOptions may override per call.
const ( // MissingTTLProceed continues after delete: Allow re-runs once; Wait does // not sleep and proceeds to Allow once; Peek returns an empty Result. MissingTTLProceed MissingTTLPolicy = iota + 1 // MissingTTLError returns ErrMissingTTL after delete. MissingTTLError )
type Option ¶
type Option func(*options)
Option configures the rate limiter at construction time.
func WithConfig ¶
WithConfig sets a static configuration snapshot. Non-zero fields of cfg override the values set by the convenience options. Prefer WithConfigSource when using caerus-framework-configuration with hot-reload.
func WithConfigSource ¶
func WithConfigSource(name, path string, opts ...SourceOption) Option
WithConfigSource binds this component to a named configuration source and registers that source with the configuration component (via the framework's ConfigSourceRegistrar pass during argv absorption). Declares a dependency on "configuration".
func WithForceMemory ¶
WithForceMemory enables or disables break-glass sticky-note primary (force_memory). When Valkey is wired but Client() is nil at Init, this must be true or Init fails. At runtime, force_memory prefers the memory path.
func WithKeyPrefix ¶
WithKeyPrefix sets the logical key prefix placed between the valkey peer's own key prefix and the caller's key (default "rl"). A trailing ":" is trimmed.
func WithLogger ¶
WithLogger overrides the logger used for component diagnostics. By default the component logs through the framework logs component (declared in GetDependencies); WithLogger is an explicit override for tests and embedded use and wins over the framework logger. slog.Default() remains the fallback only when neither is available.
func WithMaxKeyLength ¶
WithMaxKeyLength sets the maximum byte length of the logical key (default 256). Oversized keys are rejected with an error, never truncated.
func WithMemoryMapFullPolicy ¶
WithMemoryMapFullPolicy seeds memory_map_full_policy ("allow" or "deny"). Required at Init when use_memory_fallback or force_memory is true.
func WithMemoryMaxEntries ¶
WithMemoryMaxEntries sets the hard cap on distinct keys in the in-process map (default 10000).
func WithMetricsEnabled ¶
WithMetricsEnabled toggles the metrics catalogue. When disabled, Metrics() returns nil. Default: enabled.
func WithName ¶
WithName sets a custom component name, allowing multiple rate-limiter instances in the same process. The default name is "http-ratelimiter" (ComponentName). Retrieve named instances with GetByName[*cf_http_ratelimiter.RateLimiter](fw, "sessions").
func WithUseMemoryFallback ¶
WithUseMemoryFallback enables or disables the sticky-note engine (use_memory_fallback). This is the capability flag: MemoryFallback and memory-only chassis need it on. It does not remove the valkey dependency — use WithoutValkeyPeer when the process omits valkey from the framework graph.
func WithValkeyName ¶
WithValkeyName binds the limiter to a valkey component with the given name (WithName on the valkey side). The default is the valkey ComponentName ("valkey").
func WithWaitDelayFunc ¶
func WithWaitDelayFunc(fn WaitDelayFunc) Option
WithWaitDelayFunc installs an app-supplied callback that decides how long Wait sleeps before retrying Allow (or aborts it). A nil callback uses the built-in jittered sleep. See WaitDelayFunc.
func WithWaitJitterMax ¶
WithWaitJitterMax caps the random extra sleep Wait adds to ResetIn (default 1s, ~10% of ResetIn). 0 disables jitter for deterministic tests.
func WithWaitMissingTTLPolicy ¶
WithWaitMissingTTLPolicy seeds wait_missing_ttl_policy ("proceed" or "error"). Required at Init.
func WithoutValkeyPeer ¶
func WithoutValkeyPeer() Option
WithoutValkeyPeer omits valkey from GetDependencies. Use when the process has no valkey component (laptop / single-replica sticky-note chassis). Init then requires use_memory_fallback=true. Wrong: omit valkey from Components but leave the default dependency — Validate fails. Right: WithoutValkeyPeer + WithUseMemoryFallback(true) + explicit memory_map_full_policy + wait_missing_ttl_policy.
type RateLimiter ¶
type RateLimiter struct {
// contains filtered or unexported fields
}
RateLimiter is the caerus-framework-http-ratelimiter component. It counts attempts for logical keys in a shared store (a cf_valkey.CFValkey peer by default; an in-process map when force_memory / memory-only / MemoryFallback) and reports allow/deny plus time-until-reset. It holds the valkey peer component (never a client snapshot) and builds every command through the peer's live Client() and prefix-aware Key(), so reconnects and key prefixes stay consistent.
func New ¶
func New(opts ...Option) *RateLimiter
New creates a rate-limiter component. The valkey peer (or memory path) is resolved at Init, not here.
func (*RateLimiter) Allow ¶
func (c *RateLimiter) Allow(ctx context.Context, key string, limit int64, window time.Duration) (Result, error)
Allow increments the counter for key and reports whether Count <= limit inside window. An empty key or a key longer than MaxKeyLength is an error (no truncation). A limit <= 0 treats rate limiting as off for this call: always allowed, no storage access, counted only in disabled_total. Transport errors are returned to the caller — fail-open/fail-closed policy belongs to the app (see AllowWithPolicy and Middleware).
func (*RateLimiter) AllowWithPolicy ¶
func (c *RateLimiter) AllowWithPolicy(ctx context.Context, key string, limit int64, window time.Duration, policy StorageErrorPolicy) (Result, error)
AllowWithPolicy is Allow with an explicit storage-error policy argument, for call sites that cannot use the HTTP middleware. On a primary-store error it applies the policy: StorageFailOpen returns Allowed=true, StorageFailClosed returns the error, StorageMemoryFallback delegates to the in-process memory limiter (requires use_memory_fallback=true) using the component's configured fallback sizing. limit <= 0 still short-circuits (disabled_total only) before any policy logic.
func (*RateLimiter) AllowWithPolicyOpts ¶
func (c *RateLimiter) AllowWithPolicyOpts(ctx context.Context, key string, limit int64, window time.Duration, policy StorageErrorPolicy, memory MemoryFallbackConfig) (Result, error)
AllowWithPolicyOpts is AllowWithPolicy with per-call MemoryFallbackConfig overrides (wired from MiddlewareConfig.Memory).
func (*RateLimiter) ForceMemory ¶
func (c *RateLimiter) ForceMemory() bool
ForceMemory reports whether break-glass sticky-note primary is enabled.
func (*RateLimiter) GetDependencies ¶
func (c *RateLimiter) GetDependencies() []string
GetDependencies implements cf.Dependencies. Always depends on logs, and on configuration when WithConfigSource is set. Depends on the valkey peer unless WithoutValkeyPeer was used (memory-only chassis). Peer names are fixed at construction, so the graph is stable before Init.
func (*RateLimiter) GetInitOrderStage ¶
func (c *RateLimiter) GetInitOrderStage() cf.Stage
GetInitOrderStage implements cf.CaerusComponent.
func (*RateLimiter) HashIPKeys ¶
func (c *RateLimiter) HashIPKeys() bool
HashIPKeys reports the configured hash_ip_keys toggle. The component does not hash keys itself (the HMAC secret is app-owned); apps read this flag in their KeyFunc and use KeyHasher when true.
func (*RateLimiter) Health ¶
func (c *RateLimiter) Health(ctx context.Context) error
Health implements cf.HealthProvider. It reports unhealthy before Init or after Shutdown. After Init in memory-only / force_memory sticky mode it reports healthy (the process-local map is ready). With a Valkey primary it delegates to the peer's health (a real PING).
func (*RateLimiter) Init ¶
func (c *RateLimiter) Init(ctx context.Context, fw *cf.CaerusFramework) error
Init implements cf.CaerusComponent. It subscribes to the framework logs component, applies the bound configuration source, validates required policies, and resolves the valkey peer when required.
func (*RateLimiter) Key ¶
func (c *RateLimiter) Key(logical string) string
Key builds the storage key for a logical key: the valkey peer's prefix-aware Key() plus this component's key prefix (e.g. portal:rl:login:<hex>). Before Init (memory mode or key-helper use) it falls back to a plain ":"-join.
func (*RateLimiter) Metrics ¶
func (c *RateLimiter) Metrics() []cf_observability.Metric
Metrics implements cf_observability.MetricsProvider. It returns nil before Init / after Shutdown, and also when metrics_enabled is false (a reload can flip enablement live). Low-cardinality labels only — never raw keys, IPs, or emails. Counters appear at zero until first fired so the series are always present while initialized.
func (*RateLimiter) Name ¶
func (c *RateLimiter) Name() string
Name implements cf.CaerusComponent. Returns the custom name set via WithName, or the default ComponentName ("http-ratelimiter") if no custom name was set.
func (*RateLimiter) OnConfigReload ¶
func (c *RateLimiter) OnConfigReload(source string, cfg any)
OnConfigReload implements cf.ConfigReloader. It re-applies the module tunables from the bound configuration source. Invalid required policies keep last-good settings. No connection is rebuilt: the valkey peer owns client rotation.
func (*RateLimiter) Peek ¶
Peek reads the current counter and TTL for key without incrementing it. A missing or expired key reports Count 0 and ResetIn 0. Allowed is always false (Peek has no limit to compare against). Used by Wait and useful for dashboards and pre-flight checks.
func (*RateLimiter) RegisterConfigSources ¶
func (c *RateLimiter) RegisterConfigSources(conf any) error
RegisterConfigSources implements cf.ConfigSourceRegistrar. The framework calls it during argv absorption; it registers this component's configuration source (name, path, env prefix, format, Owner) with the configuration component. No-op when no source is bound.
func (*RateLimiter) Reset ¶
func (c *RateLimiter) Reset(ctx context.Context, key string) error
Reset deletes the counter for key (successful login / admin unlock). A missing key is a success (idempotent). The error string never includes the logical key (avoid leaking hashed identities into logs).
func (*RateLimiter) Shutdown ¶
func (c *RateLimiter) Shutdown(ctx context.Context) error
Shutdown implements cf.CaerusComponent. It unsubscribes the logs subscription and drops the valkey peer. Further use returns an error.
func (*RateLimiter) UseMemoryFallback ¶
func (c *RateLimiter) UseMemoryFallback() bool
UseMemoryFallback reports whether the sticky-note engine is enabled.
func (*RateLimiter) Wait ¶
func (c *RateLimiter) Wait(ctx context.Context, key string, limit int64, window time.Duration) error
Wait blocks until a single Allow would succeed, then performs that Allow once, or returns when ctx is done. It must not keep calling Allow while denied (each Allow increments the counter): it peeks, sleeps on ResetIn plus a small jitter, then tries Allow once. Sleep is interruptible by ctx. A limit <= 0 returns immediately (limiter off for this call).
type Result ¶
type Result struct {
// Allowed is true when Count does not exceed the limit for the window.
// From Peek it is always false: Peek has no limit to compare against.
Allowed bool
// Count is the (incremented, for Allow) request count within the window.
Count int64
// ResetIn is the time remaining until the window resets (for Retry-After).
ResetIn time.Duration
}
Result reports the outcome of an Allow or Peek call.
type SourceOption ¶
type SourceOption func(*sourceOptions)
SourceOption configures the self-registered configuration source created by WithConfigSource.
func WithSourceEnvPrefix ¶
func WithSourceEnvPrefix(prefix string) SourceOption
WithSourceEnvPrefix sets the environment overlay prefix for the source (default: the uppercase source name with "-" replaced by "_", plus "_"). An empty prefix disables env overlay.
func WithSourceFormat ¶
func WithSourceFormat(f cf_configuration.Format) SourceOption
WithSourceFormat forces the file format instead of inferring it from the path extension (".yaml"/".yml" → YAML; anything else JSON).
type StorageErrorPolicy ¶
type StorageErrorPolicy int
StorageErrorPolicy selects what happens when the primary store (Valkey) errors or is unavailable. It is the main safety switch for "Valkey is dead — what now?" and must be set explicitly per call site (AllowWithPolicy always takes one; Middleware errors if OnStoreError is unset). There is no silent FailOpen.
const ( // StorageFailOpen treats a store error as allowed. Site stays up; // attackers also get in with no limits. Typical for IP middleware on login // routes where availability wins. StorageFailOpen StorageErrorPolicy = iota // StorageFailClosed treats a store error as denied / returns an error. // Safer; real users may see 429/503 until the store is back. Typical for // webhook intake where failing open would feed an attacker. StorageFailClosed // StorageMemoryFallback uses the process-local memory limiter for that // call. Still some limits, only on this one server. Requires use_memory_fallback=true // on the component. Typical for login lockout where a coarse in-process // ceiling is better than none. StorageMemoryFallback )
type WaitDelayFunc ¶
type WaitDelayFunc func(ctx context.Context, key string, base, jittered time.Duration) (sleep time.Duration, err error)
WaitDelayFunc is called when Wait must pause before retrying Allow. base is the reset-in from the store (Peek/Allow); jittered is base plus the built-in jitter (if enabled). Return the duration to sleep (may be 0), or an error to abort Wait. A nil function sleeps jittered (or base when jitter is disabled) with ctx.
type WaitOptions ¶
type WaitOptions struct {
// MissingTTLPolicy overrides wait_missing_ttl_policy when non-nil.
MissingTTLPolicy *MissingTTLPolicy
// DelayFunc overrides the component WaitDelayFunc when non-nil. A non-nil
// function that is itself nil-valued is not expressible; omit to inherit.
DelayFunc WaitDelayFunc
// contains filtered or unexported fields
}
WaitOptions overrides Wait behaviour for a single call. Nil pointer fields inherit the component defaults.