How do I implement retries and circuit breakers in Go?

Go, retries, circuit breakers, Go programming, error handling, resilience
This content explains how to implement retries and circuit breakers in Go, enhancing the resilience of applications.

package main

import (
    "errors"
    "fmt"
    "time"
)

type CircuitBreaker struct {
    isOpen       bool
    failureCount int
    threshold    int
    timeout      time.Duration
    lastAttempt  time.Time
}

func NewCircuitBreaker(threshold int, timeout time.Duration) *CircuitBreaker {
    return &CircuitBreaker{
        threshold: threshold,
        timeout:   timeout,
    }
}

func (cb *CircuitBreaker) Call(do func() error) error {
    if cb.isOpen && time.Since(cb.lastAttempt) < cb.timeout {
        return errors.New("circuit is open, call failed")
    }
    
    err := do()
    if err != nil {
        cb.failureCount++
        cb.lastAttempt = time.Now()

        if cb.failureCount >= cb.threshold {
            cb.isOpen = true
            return errors.New("circuit opened due to failure")
        }
        return err
    }

    cb.failureCount = 0
    cb.isOpen = false
    return nil
}

func main() {
    cb := NewCircuitBreaker(3, 5*time.Second)

    for i := 0; i < 10; i++ {
        err := cb.Call(func() error {
            // Simulate a faulty service call:
            if time.Now().Second()%2 == 0 {
                return errors.New("simulated service failure")
            }
            fmt.Println("Service call succeeded")
            return nil
        })
        if err != nil {
            fmt.Println(err)
            time.Sleep(1 * time.Second) // Wait before retrying
        }
    }
}
    

Go retries circuit breakers Go programming error handling resilience