mirror of
https://github.com/smallnest/rpcx.git
synced 2025-09-26 20:21:14 +08:00

struct ConsecCircuitBreaker{} cannot pass the race test below: go test ./client -race -run TestCircuitBreakerRace$ Split compond type value lastFailureTime (time.Time) to second and nano, then we can use atomic.
76 lines
1.4 KiB
Go
76 lines
1.4 KiB
Go
package client
|
|
|
|
import (
|
|
"errors"
|
|
"math/rand"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestConsecCircuitBreaker(t *testing.T) {
|
|
count := -1
|
|
fn := func() error {
|
|
count++
|
|
if count >= 5 && count < 10 {
|
|
return nil
|
|
}
|
|
|
|
return errors.New("test error")
|
|
}
|
|
|
|
cb := NewConsecCircuitBreaker(5, 100*time.Millisecond)
|
|
|
|
for i := 0; i < 25; i++ {
|
|
err := cb.Call(fn, 200*time.Millisecond)
|
|
switch {
|
|
case i < 5:
|
|
if err.Error() != "test error" {
|
|
t.Fatalf("expect %v, got %v", "test error", err)
|
|
}
|
|
case i >= 5 && i < 10:
|
|
if err != ErrBreakerOpen {
|
|
t.Fatalf("expect %v, got %v", ErrBreakerOpen, err)
|
|
}
|
|
case i >= 10 && i < 15:
|
|
if err != nil {
|
|
t.Fatalf("expect success, got %v", err)
|
|
}
|
|
case i >= 15 && i < 20:
|
|
if err.Error() != "test error" {
|
|
t.Fatalf("expect %v, got %v", "test error", err)
|
|
}
|
|
case i >= 20 && i < 25:
|
|
if err != ErrBreakerOpen {
|
|
t.Fatalf("expect %v, got %v", ErrBreakerOpen, err)
|
|
}
|
|
}
|
|
|
|
if i == 9 { // expired
|
|
time.Sleep(150 * time.Millisecond)
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestCircuitBreakerRace(t *testing.T) {
|
|
cb := NewConsecCircuitBreaker(2, 50*time.Millisecond)
|
|
routines := 100
|
|
loop := 100000
|
|
|
|
fn := func() error {
|
|
if rand.Intn(2) == 1 {
|
|
return nil
|
|
}
|
|
return errors.New("test error")
|
|
}
|
|
|
|
for r := 0; r < routines; r++ {
|
|
go func() {
|
|
for i := 0; i < loop; i++ {
|
|
cb.Call(fn, 100*time.Millisecond)
|
|
}
|
|
}()
|
|
}
|
|
}
|