breaker

package
v0.9.13 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package breaker provides a keyed circuit breaker for guarding reconcilers against remote dependencies returning transient errors.

Transport integrates it as an http.RoundTripper with one circuit per request host, surfacing every transient failure as a *Error carrying the backoff to wait. Once a host's circuit opens, requests short-circuit without reaching the network — granting a single half-open probe per backoff window — so a backlog of keys collapses to a trickle of probes instead of hammering an unhealthy dependency. The delays suit workqueue.RequeueNotBefore floors.

For non-HTTP dependencies, use a Breaker directly: gate each attempt with Allow and report its outcome with RecordSuccess or RecordFailure.

Example
package main

import (
	"fmt"
	"time"

	"chainguard.dev/driftlessaf/breaker"
)

func main() {
	b := breaker.New(
		breaker.WithFailureThreshold(3),
		breaker.WithBaseDelay(time.Second),
		breaker.WithMaxDelay(time.Minute),
	)

	const host = "packages.example.dev"
	for range 3 {
		b.RecordFailure(host)
	}
	ok, _ := b.Allow(host)
	fmt.Println("allowed after three failures:", ok)

	b.RecordSuccess(host)
	ok, _ = b.Allow(host)
	fmt.Println("allowed after a success:", ok)

}
Output:
allowed after three failures: false
allowed after a success: true

Index

Examples

Constants

View Source
const (
	// DefaultFailureThreshold is the number of consecutive failures that trips
	// a key's circuit open.
	DefaultFailureThreshold = 5
	// DefaultBaseDelay is the initial backoff, doubling per consecutive failure.
	DefaultBaseDelay = 30 * time.Second
	// DefaultMaxDelay caps the backoff; it matches workqueue.MaximumRequeueFloor.
	DefaultMaxDelay = time.Hour
)

Defaults for New.

Variables

This section is empty.

Functions

This section is empty.

Types

type Breaker

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

Breaker is a keyed circuit breaker for transient failures against remote dependencies. Once a key reaches the failure threshold, Allow short-circuits with a backoff delay until a single half-open probe per backoff window succeeds. State is in-memory and per-process. Safe for concurrent use.

func New

func New(opts ...Option) *Breaker

New returns a Breaker with the default tuning, adjusted by opts.

func (*Breaker) Allow

func (b *Breaker) Allow(key string) (bool, time.Duration)

Allow reports whether an attempt for key may proceed. When it returns false, the returned delay is the remaining cooldown.

func (*Breaker) RecordFailure

func (b *Breaker) RecordFailure(key string) time.Duration

RecordFailure records a failure for key and returns the backoff to wait before retrying.

func (*Breaker) RecordSuccess

func (b *Breaker) RecordSuccess(key string)

RecordSuccess marks key healthy, closing its circuit.

type Error

type Error struct {
	// Key identifies the circuit: the request's host.
	Key string
	// StatusCode is the transient status code received, or zero when no
	// response was received (open circuit or transport error).
	StatusCode int
	// RetryAfter is the backoff to wait before retrying the host, suited to a
	// workqueue.RequeueNotBefore floor.
	RetryAfter time.Duration
	// Err is the underlying transport error, if any.
	Err error
}

Error is a transient failure reported by Transport: an open circuit, a transport-level error, or a transient status code (5xx/429).

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type Option

type Option func(*Breaker)

Option configures a Breaker.

func WithBaseDelay

func WithBaseDelay(d time.Duration) Option

WithBaseDelay sets the initial backoff delay.

func WithFailureThreshold

func WithFailureThreshold(n int) Option

WithFailureThreshold sets the number of consecutive failures that trips a key's circuit open.

func WithMaxDelay

func WithMaxDelay(d time.Duration) Option

WithMaxDelay caps the backoff delay.

type Transport

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

Transport is an http.RoundTripper guarding requests with a per-host Breaker. Transport-level failures and transient status codes (5xx/429) count against the host's circuit; any other response (including 4xx) closes it. Once open, requests short-circuit without reaching the network until a half-open probe succeeds.

Unlike a conventional RoundTripper, transient-status responses are consumed and returned as a *Error so every failure carries its backoff.

func NewTransport

func NewTransport(base http.RoundTripper, opts ...Option) *Transport

NewTransport returns a Transport wrapping base (http.DefaultTransport when nil) with a Breaker configured by opts.

Example
package main

import (
	"errors"
	"net/http"
	"time"

	"chainguard.dev/driftlessaf/breaker"
)

func main() {
	client := &http.Client{
		Timeout:   time.Minute,
		Transport: breaker.NewTransport(nil, breaker.WithFailureThreshold(3)),
	}

	resp, err := client.Get("https://packages.example.dev/os/x86_64/APKINDEX.tar.gz")
	var berr *breaker.Error
	if errors.As(err, &berr) {
		// Transient failure: requeue not before berr.RetryAfter.
		return
	}
	if err == nil {
		resp.Body.Close()
	}
}

func (*Transport) RoundTrip

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements http.RoundTripper.

Jump to

Keyboard shortcuts

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