breaker

package
v1.0.0 Latest Latest
Warning

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

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

Documentation

Overview

Package breaker stops calling a dependency that is clearly down.

The problem it solves is not the failing dependency — it is what your service does about it. Every request waits for a three-second timeout, so every worker is blocked waiting, so the service stops answering the endpoints that do not need that dependency at all. One failing downstream has taken out everything.

An open breaker fails those calls immediately, with KindUnavailable, which frees the workers and gives the dependency room to recover.

closed    calls pass. Consecutive failures count toward the threshold.
open      calls fail at once. After Cooldown, one probe is allowed.
half-open one call probes. Success closes; failure re-opens.
Example

After enough consecutive failures the breaker opens and stops calling the dependency at all, which frees the workers it was blocking.

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/IncepTools/go/src/core/errs"
	"github.com/IncepTools/go/src/reliability/breaker"
)

func main() {
	b := breaker.New(breaker.Options{
		Name: "pricing-api", Threshold: 3, Cooldown: time.Minute,
	})
	ctx := context.Background()

	for range 3 {
		_ = b.Do(ctx, func(context.Context) error {
			return errs.Unavailable("connection refused")
		})
	}
	fmt.Println("state:", b.State())

	called := false
	err := b.Do(ctx, func(context.Context) error { called = true; return nil })

	fmt.Println("dependency called:", called)
	fmt.Println("code:", errs.CodeOf(err))
}
Output:
state: open
dependency called: false
code: CIRCUIT_OPEN

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Value

func Value[T any](ctx context.Context, b *Breaker, fn func(ctx context.Context) (T, error)) (T, error)

Value is Do for a function that returns a result.

Types

type Breaker

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

Breaker guards one dependency. Create one per dependency, not one per service: a shared breaker lets an unrelated failure block a healthy call.

func New

func New(opt Options) *Breaker

New builds a breaker.

Example (ClientErrorsDoNotCount)

A 404 from a dependency is a perfectly healthy answer. Counting it would mean a client asking for missing things repeatedly takes the dependency out for everyone.

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/IncepTools/go/src/core/errs"
	"github.com/IncepTools/go/src/reliability/breaker"
)

func main() {
	b := breaker.New(breaker.Options{Threshold: 2, Cooldown: time.Minute})

	for range 10 {
		_ = b.Do(context.Background(), func(context.Context) error {
			return errs.NotFound("no price for that SKU")
		})
	}
	fmt.Println(b.State())
}
Output:
closed

func (*Breaker) Do

func (b *Breaker) Do(ctx context.Context, fn func(ctx context.Context) error) error

Do runs fn unless the breaker is open.

func (*Breaker) State

func (b *Breaker) State() State

State reports the current state.

type Options

type Options struct {
	// Name identifies the dependency in logs and in the error.
	Name string
	// Threshold is the consecutive failures that open the breaker. Default 5.
	Threshold int
	// Cooldown is how long it stays open before probing. Default 30s.
	Cooldown time.Duration
	// Counts decides whether an error counts toward the threshold.
	//
	// The default counts only unavailability and timeouts. A 404 from a
	// dependency is a perfectly healthy answer and must not open a breaker —
	// counting it means a client asking for missing things repeatedly takes
	// the dependency out for everyone.
	Counts func(error) bool
	// OnStateChange is called on every transition.
	OnStateChange func(from, to State)
}

Options configures a breaker.

type State

type State string

State is the breaker's position.

const (
	// Closed is normal operation: calls pass, and consecutive failures count
	// toward the threshold.
	Closed State = "closed"
	// Open is failing fast: calls are refused without touching the
	// dependency, which is what frees the workers it was blocking.
	Open State = "open"
	// HalfOpen is one probe in flight. Success closes the breaker; failure
	// re-opens it.
	HalfOpen State = "half-open"
)

Jump to

Keyboard shortcuts

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