Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How long dose it recover when it breaker #61

Open
YuanWeiKang opened this issue Mar 20, 2020 · 4 comments
Open

How long dose it recover when it breaker #61

YuanWeiKang opened this issue Mar 20, 2020 · 4 comments

Comments

@YuanWeiKang
Copy link

it's code

func TestBreaker22(t *testing.T) {
	brk := NewBreakerWithOptions(&Options{
		ShouldTrip: RateTripFunc(0.6, 100),
	})
	flag := 0
	start := time.Now().UnixNano()
	for i := 0; i < 200; i++ {
		err := brk.Call(func() error {
			return testDoSomething(flag)
		}, 0)

		last := atomic.LoadInt64(&brk.lastFailure)
		since := brk.Clock.Now().Sub(time.Unix(0, last))
		trip := atomic.LoadInt32(&brk.tripped)
		fmt.Printf("i:%d, trip:%d, last:%d, since:%+v, backOff:%+v, flag:%d, error:%s\n", i, trip, last, since, brk.nextBackOff, flag, err)

		if err == nil && brk.tripped == 0 {
			fmt.Printf("i:%d, trip:%d, duration:%d\n", i, brk.tripped, time.Now().UnixNano()-start)
			//break
		}
		if err != nil && strings.Contains(err.Error(), "breaker open") {
			flag = 1
			//time.Sleep(200 * time.Millisecond)
		}
	}
}

func testDoSomething(flag int) error {
	if flag == 0 {
		return fmt.Errorf("bad request")
	} else {
		return nil
	}
}

How do I calculate the recovery time?

@YuanWeiKang YuanWeiKang changed the title How long dose it recover where it breaker How long dose it recover when it breaker Mar 20, 2020
@macdabby
Copy link

macdabby commented Jun 4, 2020

I'm not sure what the recovery time is but it looks like it's not configurable and not documented.

@macdabby
Copy link

macdabby commented Jun 4, 2020

This is where it is defined:

if cb.nextBackOff != backoff.Stop && since > cb.nextBackOff {

@macdabby
Copy link

macdabby commented Jun 4, 2020

it seems that it's using exponential backoff by default:

// attempt to retry. A breaker created with NewBreaker will use an exponential backoff

@apundir
Copy link

apundir commented Aug 4, 2020

The backoff time is defined by backing backing.ExponentialBackOff , it's assigned with default values and further customized at:

if options.BackOff == nil {
b := backoff.NewExponentialBackOff()
b.InitialInterval = defaultInitialBackOffInterval
b.MaxElapsedTime = defaultBackoffMaxElapsedTime
b.Clock = options.Clock
b.Reset()
options.BackOff = b
}

The actual backoff time is controlled by ExponentialBackOff type. Entire logic is documented and explained in official documentation. Following is the snippet from the documentation that explains this logic

Example: Given the following default arguments, for 10 tries the sequence will be, and assuming we go over the MaxElapsedTime on the 10th try:

Request #  RetryInterval (seconds)  Randomized Interval (seconds)

 1          0.5                     [0.25,   0.75]
 2          0.75                    [0.375,  1.125]
 3          1.125                   [0.562,  1.687]
 4          1.687                   [0.8435, 2.53]
 5          2.53                    [1.265,  3.795]
 6          3.795                   [1.897,  5.692]
 7          5.692                   [2.846,  8.538]
 8          8.538                   [4.269, 12.807]
 9         12.807                   [6.403, 19.210]
10         19.210                   backoff.Stop

It's also worth noting that default value of InitialInterval is 500ms and that of MaxElapsedTime is 0 in circuitbreaker. Thus table above gives you each backoff duration window with the exception that it doesn't stop growing at Request # 10 since the value of MaxElapsedTime is 0 by default in circuitbreaker. It'll keep on backing off exponentially with same logic till it attains max value of 1 minute (default from backoff) thus leading to final randomized interval between 30 and 90 seconds with default values from breaker.

You can customize these values if you wish to. Use NewBreakerWithOptions directly instead of convenient NewXXXX variant wrappers and pass your own instance of ExponentialBackOff with specific values as per your needs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants