gobreakerソース分析ノート

2351 ワード

ソニー大法オープンソースヒューズhttps://github.com/sony/gobreaker


Microsoft Circuit Breaker patternベース


3つの状態

  • Closed
  • Open
  • HalfOpen

  • 基本構成
    type Settings struct {
        Name          string  //breaker 
        MaxRequests   uint32  //  , HelfOpen 
        Interval      time.Duration  // Close , counts 
        Timeout       time.Duration  // Open timeout , HelfOpen
        ReadyToTrip   func(counts Counts) bool // Closed , 。 , Open 
        OnStateChange func(name string, from State, to State) //  
    }
    

    Counts構造体
     : Generation 
    
    type Counts struct {
        Requests             uint32 // 
        TotalSuccesses       uint32 //  
        TotalFailures        uint32 //  
        ConsecutiveSuccesses uint32 //  
        ConsecutiveFailures  uint32 //  
    }
    
    
  • toNewGeneration:新しいgenerationを生成します.主にcountsをクリアし、expiry(期限切れ)を設定します.ステータスがClosedの場合、expiryはClosedの有効期限(現在時間+interval)、ステータスがOpenの場合、expiryはOpenの有効期限(現在時間+timeout)
  • である.
  • currentState:現在のステータスを取得します.Closedでexpiryが期限切れになった場合、toNewGenerationを呼び出して新しいgenerationを生成します.Open時にexpiryが期限切れになった場合、helfOpenとします.
  • コア実行関数Execute:この関数は、3ステップbeforeRequest、実行要求、afterRequest
  • に分けられます.
    func (cb *CircuitBreaker) Execute(req func() (interface{}, error)) (interface{}, error) {
        generation, err := cb.beforeRequest()
        if err != nil {
            return nil, err
        }
    
        defer func() {
            e := recover()
            if e != nil {
                cb.afterRequest(generation, false)
                panic(e)
            }
        }()
    
        result, err := req()
        cb.afterRequest(generation, err == nil)
        return result, err
    }
    
    
  • beforeRequest:currentStateでステータスを取得し、Openの場合はエラーを直接返します.HelfOpenの場合、counts内のリクエスト数がmaxRequests以上の場合、エラーが返されます.そうでなければcountsのRequestsに1
  • を加える
  • req:取得要求結果
  • afterRequest:

  • func (cb *CircuitBreaker) afterRequest(before uint64, success bool) {
        cb.mutex.Lock()
        defer cb.mutex.Unlock()
    
        now := time.Now()
        state, generation := cb.currentState(now)
        if generation != before {
            return
        }
    
        if success {
            cb.onSuccess(state, now) //  counts
        } else {
            cb.onFailure(state, now) // Closed:  readyToTrip, Open。HelfOpen: Open 
        }
    }