circbrk-go

September 11, 2025 ยท View on GitHub

circbrk-go is a Circuit Breaker Pattern implementation for Go.

How To

package main

import (
  "sync"
  "time"

  assert "github.com/ymz-ncnk/assert/panic"
  circbrk "github.com/ymz-ncnk/circbrk-go"
)

func init() {
  assert.On = true
}

const OpenDuration = time.Second

func main() {
  cb := circbrk.New(circbrk.WithWindowSize(4),
    circbrk.WithFailureRate(0.5),
    circbrk.WithOpenDuration(OpenDuration),
    circbrk.WithSuccessThreshold(2),
  )
  // The circuit breaker starts in the closed state.
  assert.Equal(cb.State(), circbrk.Closed)

  cb.Fail()
  cb.Success()
  cb.Success()
  cb.Fail()

  // After several calls the failure rate (in this case, 2 failures out of 4
  // calls = 0.5) meets the configured threshold, so the circuit transitions to
  // the open state in which it doesn't allow requests.
  assert.Equal(cb.State(), circbrk.Open)
  assert.Equal(cb.Allowed(), false)

  // While in the open state, Fail() and Success() calls have no effect.
  cb.Fail()
  cb.Success()

  time.Sleep(OpenDuration + 200*time.Millisecond)

  // After the open duration, the circuit transitions to the half-open state.
  assert.Equal(cb.State(), circbrk.HalfOpen)

  // In the half-open state, 2 successful calls (as configured by
  // WithSuccessThreshold) are required to transition back to closed.
  assert.Equal(cb.Allowed(), true)
  // The breaker allows, so we can execute the request and notify it of a 
  // successful outcome.
  cb.Success()

  assert.Equal(cb.Allowed(), true)
  // The number of allowed attempts equals the number of required successes.
  // Any additional calls to cb.Allowed() in half-open state will return false.
  wg := sync.WaitGroup{}
  wg.Add(1)
  go func() {
    assert.Equal(cb.Allowed(), false)
    assert.Equal(cb.Allowed(), false)
    wg.Done()
  }()
  wg.Wait()
  cb.Success()

  assert.Equal(cb.State(), circbrk.Closed)
  assert.Equal(cb.Allowed(), true)

  // On any failure in the half-open state, the circuit re-enters the open
  // state.
  // cb.Fail()
  // assert.Equal(cb.Open(), true)
  // assert.Equal(cb.Allowed(), false)
}