resilience

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2026 License: MIT Imports: 4 Imported by: 0

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

View Source
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.

View Source
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

func New(cfg Config) *Breaker

New returns a Breaker in the Closed state, with invalid config fields clamped to defaults.

func (*Breaker) Allow

func (b *Breaker) Allow() (done func(failure bool), allowed bool)

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

func (b *Breaker) Record(failure bool)

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.

func (*Breaker) State

func (b *Breaker) State() State

State returns the current state. It does not advance the cooldown clock; a post-cooldown Open breaker still reports Open until the next Allow.

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
)

func (State) String

func (s State) String() string

String renders the state for logging.

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.

func NewStore

func NewStore(limit rate.Limit, burst, maxKeys int) *Store

NewStore returns a Store handing out buckets of the given rate and burst, tracking at most maxKeys keys (clamped to >= 1).

func (*Store) Len

func (s *Store) Len() int

Len reports the number of tracked keys.

func (*Store) LimiterFor

func (s *Store) LimiterFor(key string) *rate.Limiter

LimiterFor returns the token bucket for key, creating it on first sighting and promoting it to most-recently-used. Evicts the LRU key when over capacity.

Jump to

Keyboard shortcuts

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