Documentation
¶
Overview ¶
Package circuitbreaker implements the transport-agnostic Closed/Open/HalfOpen state machine shared by the HTTP and gRPC client circuit breakers. It carries no HTTP or gRPC types so both transports wrap a single, fully-unit-tested core rather than maintaining two divergent implementations.
The breaker fails fast: while Open it admits nothing and the caller returns an error immediately. It never stores or serves a previously-seen response — it is a stability primitive, not a cache.
Package ratelimit provides the bounded, LRU-evicting per-key token-bucket store shared by the HTTP and gRPC server-side rate limiters. Keeping it in one place means both transports get identical memory-safety guarantees rather than two divergent stores.
Index ¶
Constants ¶
const ( DefaultFailureThreshold = 5 DefaultCooldown = 30 * time.Second DefaultHalfOpenMax = 1 )
Default policy values, exported so the transport wrappers' Default*Config constructors reference one source of truth rather than re-typing the literals.
const DefaultMaxTrackedKeys = 8192
DefaultMaxTrackedKeys bounds the per-key store so an attacker rotating source keys cannot allocate unbounded *rate.Limiter values and exhaust memory.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Breaker ¶
type Breaker struct {
// contains filtered or unexported fields
}
Breaker is a concurrency-safe Closed/Open/HalfOpen circuit breaker.
func New ¶
New returns a Breaker in the Closed state, with invalid config fields clamped to defaults.
func (*Breaker) Allow ¶
Allow reports whether a call may proceed. When it returns allowed==true the caller MUST invoke the returned done func exactly once with the call's outcome (failure==true if the call should count against the breaker). When allowed is false the breaker is Open (or its HalfOpen trial budget is exhausted) and done is nil — the caller fails fast.
func (*Breaker) Record ¶ added in v0.1.1
Record applies an out-of-band outcome observed without a paired Allow admission — e.g. a per-message stream failure reported after the stream's establishment already delivered the trial verdict. It counts only while the breaker is Closed: Open admits nothing, and a HalfOpen trial's verdict is owned exclusively by its admitted done callbacks.
type Config ¶
type Config struct {
// FailureThreshold is the number of consecutive failures (in Closed) that
// trips the breaker Open. Clamped to >= 1; default 5.
FailureThreshold int
// Cooldown is how long the breaker stays Open before admitting a trial. It
// also bounds each HalfOpen trial window: when the trial budget is
// exhausted and no verdict has arrived within Cooldown of entering
// HalfOpen, the outstanding trial is treated as expired and the breaker
// re-opens (see Allow). Clamped to > 0; default 30s.
Cooldown time.Duration
// HalfOpenMaxRequests is the number of concurrent trial calls admitted in
// HalfOpen. Clamped to >= 1; default 1.
HalfOpenMaxRequests int
// Now is the clock. Defaults to time.Now; injected in tests so cooldown
// transitions are deterministic without sleeps.
Now func() time.Time
// OnStateChange, if set, is called on every state transition. It runs while
// the breaker's lock is held, so it MUST NOT call back into the breaker.
OnStateChange func(from, to State)
}
Config configures a Breaker. The zero value is invalid; pass it through New, which clamps unset/invalid fields to safe defaults.
type State ¶
type State int
State is the breaker's current state.
const ( // StateClosed admits all calls; consecutive failures are counted. StateClosed State = iota // StateOpen rejects all calls until the cooldown elapses. StateOpen // StateHalfOpen admits a bounded number of trial calls; the first success // closes the breaker, any failure re-opens it. StateHalfOpen )
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is a bounded, LRU-evicting map of per-key token buckets. It is mutex-guarded and caps the number of tracked keys; when full, the least-recently-used key is evicted. A re-sighted evicted key gets a fresh, full bucket — acceptable because eviction only happens under key churn.