go: Circuit-Breaker Pattern

项目结构:

断路器模式是稳定性设计模式的核心之一,核心作用:当依赖服务持续失败时,自动切断请求调用,避免级联故障、耗尽系统资源,保护核心业务流程。

它有 3 种状态:

关闭 (Closed):正常放行所有请求

打开 (Open):连续失败达到阈值,直接拦截请求,快速失败

半开 (Half-Open):超时后尝试放行少量请求,验证服务是否恢复

Go 复制代码
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Circuit-Breaker Pattern 熔断器模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/28 21:38
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : settings.go
*/
package config
 
import "time"
 
// CircuitBreakerConfig 断路器配置
type CircuitBreakerConfig struct {
    FailureThreshold int
    RecoveryTimeout  time.Duration
    SuccessThreshold int
}
 
// JewelryBusinessConfig 珠宝业务配置
type JewelryBusinessConfig struct {
    FallbackGoldPrice float64
    FailureRate       float64
}
 
// 全局单例配置
var (
    CbConfig = CircuitBreakerConfig{
        FailureThreshold: 3,
        RecoveryTimeout:  10 * time.Second,
        SuccessThreshold: 2,
    }
 
    JewelryConfig = JewelryBusinessConfig{
        FallbackGoldPrice: 628.5,
        FailureRate:       0.7,
    }
)
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Circuit-Breaker Pattern 熔断器模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/28 21:38
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : exception.go
*/
package core
 
import "fmt"
 
// ServiceErr 业务基础异常
type ServiceErr struct {
    Msg string
}
 
func (e *ServiceErr) Error() string {
    return fmt.Sprintf("service error: %s", e.Msg)
}
 
// ExternalServiceErr 第三方外部服务异常
func NewExternalServiceErr(msg string) error {
    return &ServiceErr{Msg: msg}
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Circuit-Breaker Pattern 熔断器模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/28 21:39
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : base.go
*/
package circuitbreaker
 
// State 断路器状态
type State string
 
const (
    StateClosed   State = "CLOSED"
    StateOpen     State = "OPEN"
    StateHalfOpen State = "HALF_OPEN"
)
 
// CircuitBreaker 断路器接口
type CircuitBreaker interface {
    IsAllowed() bool
    OnSuccess()
    OnFailure()
    GetState() State
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Circuit-Breaker Pattern 熔断器模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/28 21:39
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : impl.go
*/
package circuitbreaker
 
import (
    "fmt"
    "godesginpattern/circuitbreaker/config"
    "time"
)
 
// DefaultCircuitBreaker 默认断路器实现
type DefaultCircuitBreaker struct {
    failureThreshold int
    recoveryTimeout  time.Duration
    successThreshold int
 
    state         State
    failureCount  int
    successCount  int
    lastFailureTs int64
}
 
func NewDefaultCircuitBreaker() *DefaultCircuitBreaker {
    cfg := config.CbConfig
    return &DefaultCircuitBreaker{
        failureThreshold: cfg.FailureThreshold,
        recoveryTimeout:  cfg.RecoveryTimeout,
        successThreshold: cfg.SuccessThreshold,
        state:            StateClosed,
    }
}
 
func (d *DefaultCircuitBreaker) GetState() State {
    return d.state
}
 
func (d *DefaultCircuitBreaker) IsAllowed() bool {
    if d.state == StateOpen {
        now := time.Now().Unix()
        if now-d.lastFailureTs >= int64(d.recoveryTimeout.Seconds()) {
            d.state = StateHalfOpen
            d.successCount = 0
            fmt.Println("🔄 断路器超时 → 进入半开状态")
            return true
        }
        return false
    }
    return true
}
 
func (d *DefaultCircuitBreaker) OnSuccess() {
    switch d.state {
    case StateClosed:
        d.failureCount = 0
    case StateHalfOpen:
        d.successCount++
        if d.successCount >= d.successThreshold {
            fmt.Println("✅ 半开状态连续成功 → 断路器关闭")
            d.reset()
        }
    }
}
 
func (d *DefaultCircuitBreaker) OnFailure() {
    switch d.state {
    case StateClosed:
        d.failureCount++
        fmt.Printf("失败计数:%d/%d\n", d.failureCount, d.failureThreshold)
        if d.failureCount >= d.failureThreshold {
            fmt.Println("🔥 连续失败达到阈值 → 断路器打开")
            d.open()
        }
    case StateHalfOpen:
        fmt.Println("❌ 半开状态请求失败 → 重新打开断路器")
        d.open()
    }
}
 
func (d *DefaultCircuitBreaker) open() {
    d.state = StateOpen
    d.lastFailureTs = time.Now().Unix()
    d.successCount = 0
}
 
func (d *DefaultCircuitBreaker) reset() {
    d.state = StateClosed
    d.failureCount = 0
    d.successCount = 0
    d.lastFailureTs = 0
}
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Circuit-Breaker Pattern 熔断器模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/28 21:40
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : breaker_decorator.go
*/
package util
 
import (
    "fmt"
    "godesginpattern/circuitbreaker/config"
    "godesginpattern/circuitbreaker/core/circuitbreaker"
)
 
// PriceResult 金价返回结构体
type PriceResult struct {
    Status     string  `json:"status"`
    GoldPrice  float64 `json:"gold_price"`
    Message    string  `json:"message,omitempty"`
    UpdateTime string  `json:"update_time,omitempty"`
}
 
// WrapBreaker 断路器包装函数(替代Python装饰器)
func WrapBreaker(breaker circuitbreaker.CircuitBreaker, fn func() (PriceResult, error)) PriceResult {
    if !breaker.IsAllowed() {
        fmt.Printf("⚠️  断路器已打开 | 当前状态:%s → 使用兜底金价\n", breaker.GetState())
        return PriceResult{
            Status:    "fallback",
            Message:   "断路器已开启,使用兜底数据",
            GoldPrice: config.JewelryConfig.FallbackGoldPrice,
        }
    }
 
    res, err := fn()
    if err != nil {
        breaker.OnFailure()
        fmt.Printf("❌ 请求失败 | 断路器状态:%s | 异常:%v\n", breaker.GetState(), err)
        return PriceResult{
            Status:    "error",
            Message:   "第三方金价服务调用失败",
            GoldPrice: config.JewelryConfig.FallbackGoldPrice,
        }
    }
 
    breaker.OnSuccess()
    fmt.Printf("✅ 请求成功 | 断路器状态:%s\n", breaker.GetState())
    return res
}
Go 复制代码
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Circuit-Breaker Pattern 熔断器模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/28 21:41
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : inventory.go
*/
package service
 
// 库存服务
// StockResp 库存返回
type StockResp struct {
    Weight float64 `json:"weight"`
    Stock  string  `json:"stock"`
    Status string  `json:"status"`
}
 
// InventoryService 珠宝库存服务
type InventoryService struct{}
 
func NewInventoryService() *InventoryService {
    return &InventoryService{}
}
 
// CheckGoldStock 校验黄金库存
func (i *InventoryService) CheckGoldStock(weight float64) StockResp {
    return StockResp{
        Weight: weight,
        Stock:  "充足",
        Status: "success",
    }
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Circuit-Breaker Pattern 熔断器模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/28 21:41
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : price.go
*/
package service
 
import (
    "godesginpattern/circuitbreaker/config"
    "godesginpattern/circuitbreaker/core"
    "godesginpattern/circuitbreaker/core/circuitbreaker"
    "godesginpattern/circuitbreaker/util"
    "math/rand"
    "time"
)
 
// 第三方金价服务
var globalBreaker = circuitbreaker.NewDefaultCircuitBreaker()
 
// PriceService 金价服务
type PriceService struct{}
 
func NewPriceService() *PriceService {
    return &PriceService{}
}
 
// GetRealtimePrice 获取实时金价(熔断保护)
func (p *PriceService) GetRealtimePrice() util.PriceResult {
    // 包装断路器逻辑
    return util.WrapBreaker(globalBreaker, func() (util.PriceResult, error) {
        rand.Seed(time.Now().UnixNano())
        if rand.Float64() < config.JewelryConfig.FailureRate {
            return util.PriceResult{}, core.NewExternalServiceErr("第三方金价接口超时/500错误")
        }
        price := 630 + rand.Float64()*20
        return util.PriceResult{
            Status:     "success",
            GoldPrice:  float64(int(price*100)) / 100,
            UpdateTime: time.Now().Format("2006-01-02 15:04:05"),
        }, nil
    })
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Circuit-Breaker Pattern 熔断器模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/28 21:42
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : order.go
*/
package service
 
import (
    "fmt"
    "time"
)
 
// Order 订单结构体
type Order struct {
    OrderID     string  `json:"order_id"`
    UserID      string  `json:"user_id"`
    SKU         string  `json:"sku"`
    Weight      float64 `json:"weight"`
    GoldPrice   float64 `json:"gold_price"`
    TotalAmount float64 `json:"total_amount"`
    OrderStatus string  `json:"order_status"`
}
 
// OrderService 订单服务(依赖注入库存、金价服务)
type OrderService struct {
    inventory *InventoryService
    price     *PriceService
}
 
// NewOrderService 构造函数注入依赖
func NewOrderService(inv *InventoryService, price *PriceService) *OrderService {
    return &OrderService{
        inventory: inv,
        price:     price,
    }
}
 
// CreateGoldOrder 创建黄金珠宝订单
func (o *OrderService) CreateGoldOrder(userID string, weight float64, sku string) Order {
    fmt.Println("\n==================================================")
    fmt.Printf("[订单服务] 开始创建订单 | 用户:%s | 克重:%.1fg\n", userID, weight)
 
    // 1. 库存校验
    stock := o.inventory.CheckGoldStock(weight)
    fmt.Printf("[库存服务] %+v\n", stock)
 
    // 2. 获取金价(带熔断)
    priceInfo := o.price.GetRealtimePrice()
    fmt.Printf("[金价服务] %+v\n", priceInfo)
 
    // 3. 计算总价
    total := float64(int(weight*priceInfo.GoldPrice*100)) / 100
 
    // 4. 生成订单
    orderID := fmt.Sprintf("ORD%d", time.Now().Unix())
    order := Order{
        OrderID:     orderID,
        UserID:      userID,
        SKU:         sku,
        Weight:      weight,
        GoldPrice:   priceInfo.GoldPrice,
        TotalAmount: total,
        OrderStatus: "PENDING_PAYMENT",
    }
    fmt.Printf("[订单服务] 订单创建成功:%+v\n", order)
    return order
}

调用:

Go 复制代码
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Circuit-Breaker Pattern 熔断器模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/28 21:43
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : circuitbreakerbll.go
*/
package bll
 
import (
    "fmt"
    "godesginpattern/circuitbreaker/service"
    "time"
)
 
// CircuitBreakerBll 业务入口封装类
type CircuitBreakerBll struct{}
 
// InitDependencies DI依赖注入容器
func (c *CircuitBreakerBll) InitDependencies() *service.OrderService {
    inv := service.NewInventoryService()
    price := service.NewPriceService()
    orderSvc := service.NewOrderService(inv, price)
    return orderSvc
}
 
// Demo 模拟连续下单测试
func (c *CircuitBreakerBll) Demo() {
    fmt.Println("=== 企业级珠宝订单系统(断路器模式保护)===\n")
    orderSvc := c.InitDependencies()
 
    // 循环10次下单
    for i := 1; i <= 10; i++ {
        fmt.Printf("\n====== 第 %d 次下单请求 ======\n", i)
        order := orderSvc.CreateGoldOrder(
            fmt.Sprintf("USER_%d", i),
            10.0,
            "GOLD_999_001",
        )
        fmt.Printf("✅ 最终订单结果:%+v\n", order)
        time.Sleep(1 * time.Second)
    }
}
 
func CircuitBreakerMain() {
    bll := &CircuitBreakerBll{}
    bll.Demo()
}
  

输出: