func (b *breaker) Timeout() {
	b.error(true, b.options.ShouldTrip)
}
Timeout records a timeout and decreases the concurrency counter by one
package circuitbreaker
import (
	"sync/atomic"
	"time"
	"github.com/bytedance/gopkg/lang/syncx"
)
const (
	defaultCoolingTimeout = time.Second * 5
	defaultDetectTimeout = time.Millisecond * 200
	defaultHalfOpenSuccesses = 2
)
type breaker struct {
	rw syncx.RWMutex
	metricer metricer  
	state           State      
	openTime        time.Time  
	lastRetryTime   time.Time  
	halfopenSuccess int32      
	isFixed         bool
	options Options
	now func() time.Time  
}
func newBreaker(options Options) (*breaker, error) {
	if options.Now == nil {
		options.Now = time.Now
	}
	if options.BucketTime <= 0 {
		options.BucketTime = defaultBucketTime
	}
	if options.BucketNums <= 0 {
		options.BucketNums = defaultBucketNums
	}
	if options.CoolingTimeout <= 0 {
		options.CoolingTimeout = defaultCoolingTimeout
	}
	if options.DetectTimeout <= 0 {
		options.DetectTimeout = defaultDetectTimeout
	}
	if options.HalfOpenSuccesses <= 0 {
		options.HalfOpenSuccesses = defaultHalfOpenSuccesses
	}
	var window metricer
	var err error
	if options.EnableShardP {
		window, err = newPerPWindowWithOptions(options.BucketTime, options.BucketNums)
	} else {
		window, err = newWindowWithOptions(options.BucketTime, options.BucketNums)
	}
	if err != nil {
		return nil, err
	}
	breaker := &breaker{
		rw:       syncx.NewRWMutex(),
		metricer: window,
		now:      options.Now,
		state:    Closed,
	}
	breaker.options = Options{
		BucketTime:                options.BucketTime,
		BucketNums:                options.BucketNums,
		CoolingTimeout:            options.CoolingTimeout,
		DetectTimeout:             options.DetectTimeout,
		HalfOpenSuccesses:         options.HalfOpenSuccesses,
		ShouldTrip:                options.ShouldTrip,
		ShouldTripWithKey:         options.ShouldTripWithKey,
		BreakerStateChangeHandler: options.BreakerStateChangeHandler,
		Now:                       options.Now,
	}
	return breaker, nil
}
func (b *breaker) Succeed() {
	rwx := b.rw.RLocker()
	rwx.Lock()
	switch b.State() {
	case Open:  
		rwx.Unlock()
	case HalfOpen:
		rwx.Unlock()
		b.rw.Lock()
		if b.State() == HalfOpen {
			atomic.AddInt32(&b.halfopenSuccess, 1)
			if atomic.LoadInt32(&b.halfopenSuccess) >= b.options.HalfOpenSuccesses {
				if b.options.BreakerStateChangeHandler != nil {
					go b.options.BreakerStateChangeHandler(HalfOpen, Closed, b.metricer)
				}
				b.metricer.Reset()
				atomic.StoreInt32((*int32)(&b.state), int32(Closed))
			}
		}
		b.rw.Unlock()
	case Closed:
		b.metricer.Succeed()
		rwx.Unlock()
	}
}
func (b *breaker) error(isTimeout bool, trip TripFunc) {
	rwx := b.rw.RLocker()
	rwx.Lock()
	if isTimeout {
		b.metricer.Timeout()
	} else {
		b.metricer.Fail()
	}
	switch b.State() {
	case Open:  
		rwx.Unlock()
	case HalfOpen:  
		rwx.Unlock()
		b.rw.Lock()
		if b.State() == HalfOpen {
			if b.options.BreakerStateChangeHandler != nil {
				go b.options.BreakerStateChangeHandler(HalfOpen, Open, b.metricer)
			}
			b.openTime = b.now()
			atomic.StoreInt32((*int32)(&b.state), int32(Open))
		}
		b.rw.Unlock()
	case Closed:  
		if trip != nil && trip(b.metricer) {
			rwx.Unlock()
			b.rw.Lock()
			if b.State() == Closed {
				if b.options.BreakerStateChangeHandler != nil {
					go b.options.BreakerStateChangeHandler(Closed, Open, b.metricer)
				}
				b.openTime = b.now()
				atomic.StoreInt32((*int32)(&b.state), int32(Open))
			}
			b.rw.Unlock()
		} else {
			rwx.Unlock()
		}
	}
}
func (b *breaker) Fail() {
	b.error(false, b.options.ShouldTrip)
}
func (b *breaker) FailWithTrip(trip TripFunc) {
	b.error(false, trip)
}