diff --git a/v2/distributed_gobreaker_test.go b/v2/distributed_gobreaker_test.go index d242a6f..164f726 100644 --- a/v2/distributed_gobreaker_test.go +++ b/v2/distributed_gobreaker_test.go @@ -1,65 +1,14 @@ package gobreaker import ( - "context" "errors" "testing" "time" "github.com/alicebob/miniredis/v2" - "github.com/go-redsync/redsync/v4" - "github.com/go-redsync/redsync/v4/redis/goredis/v9" - "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" ) -type storeAdapter struct { - ctx context.Context - client *redis.Client - rs *redsync.Redsync - mutex map[string]*redsync.Mutex -} - -func newStoreAdapter(client *redis.Client) *storeAdapter { - return &storeAdapter{ - ctx: context.Background(), - client: client, - rs: redsync.New(goredis.NewPool(client)), - mutex: map[string]*redsync.Mutex{}, - } -} - -func (sa *storeAdapter) Lock(name string) error { - mutex, ok := sa.mutex[name] - if ok { - return mutex.Lock() - } - - mutex = sa.rs.NewMutex(name, redsync.WithExpiry(mutexTimeout)) - sa.mutex[name] = mutex - return mutex.Lock() -} - -func (sa *storeAdapter) Unlock(name string) error { - mutex, ok := sa.mutex[name] - if ok { - var err error - ok, err = mutex.Unlock() - if ok && err == nil { - return nil - } - } - return errors.New("unlock failed") -} - -func (sa *storeAdapter) GetData(name string) ([]byte, error) { - return sa.client.Get(sa.ctx, name).Bytes() -} - -func (sa *storeAdapter) SetData(name string, data []byte) error { - return sa.client.Set(sa.ctx, name, data, 0).Err() -} - var redisServer *miniredis.Miniredis func setUpDCB() *DistributedCircuitBreaker[any] { @@ -69,11 +18,7 @@ func setUpDCB() *DistributedCircuitBreaker[any] { panic(err) } - client := redis.NewClient(&redis.Options{ - Addr: redisServer.Addr(), - }) - - store := newStoreAdapter(client) + store := NewRedisStore(redisServer.Addr()) dcb, err := NewDistributedCircuitBreaker[any](store, Settings{ Name: "TestBreaker", @@ -93,9 +38,8 @@ func setUpDCB() *DistributedCircuitBreaker[any] { func tearDownDCB(dcb *DistributedCircuitBreaker[any]) { if dcb != nil { - store := dcb.store.(*storeAdapter) - store.client.Close() - store.client = nil + store := dcb.store.(*RedisStore) + store.Close() } if redisServer != nil { @@ -234,11 +178,7 @@ func TestCustomDistributedCircuitBreaker(t *testing.T) { } defer mr.Close() - client := redis.NewClient(&redis.Options{ - Addr: mr.Addr(), - }) - - store := newStoreAdapter(client) + store := NewRedisStore(mr.Addr()) customDCB, err = NewDistributedCircuitBreaker[any](store, Settings{ Name: "CustomBreaker", @@ -327,11 +267,7 @@ func TestCustomDistributedCircuitBreakerStateTransitions(t *testing.T) { } defer mr.Close() - client := redis.NewClient(&redis.Options{ - Addr: mr.Addr(), - }) - - store := newStoreAdapter(client) + store := NewRedisStore(mr.Addr()) dcb, err := NewDistributedCircuitBreaker[any](store, customSt) assert.NoError(t, err) diff --git a/v2/go.mod b/v2/go.mod index 3489a6a..0d35166 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -1,25 +1,24 @@ module github.com/sony/gobreaker/v2 -go 1.22 +go 1.22.0 toolchain go1.22.10 -require github.com/stretchr/testify v1.8.4 +require ( + github.com/alicebob/miniredis/v2 v2.33.0 + github.com/go-redsync/redsync/v4 v4.13.0 + github.com/redis/go-redis/v9 v9.7.0 + github.com/stretchr/testify v1.8.4 +) require ( github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/yuin/gopher-lua v1.1.1 // indirect -) - -require ( - github.com/alicebob/miniredis/v2 v2.33.0 - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-redsync/redsync/v4 v4.13.0 github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/redis/go-redis/v9 v9.7.0 + github.com/yuin/gopher-lua v1.1.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/v2/redis_store.go b/v2/redis_store.go new file mode 100644 index 0000000..0f70f3a --- /dev/null +++ b/v2/redis_store.go @@ -0,0 +1,64 @@ +package gobreaker + +import ( + "context" + "errors" + + "github.com/go-redsync/redsync/v4" + "github.com/go-redsync/redsync/v4/redis/goredis/v9" + "github.com/redis/go-redis/v9" +) + +type RedisStore struct { + ctx context.Context + client *redis.Client + rs *redsync.Redsync + mutex map[string]*redsync.Mutex +} + +func NewRedisStore(addr string) *RedisStore { + client := redis.NewClient(&redis.Options{ + Addr: addr, + }) + return &RedisStore{ + ctx: context.Background(), + client: client, + rs: redsync.New(goredis.NewPool(client)), + mutex: map[string]*redsync.Mutex{}, + } +} + +func (rs *RedisStore) Lock(name string) error { + mutex, ok := rs.mutex[name] + if ok { + return mutex.Lock() + } + + mutex = rs.rs.NewMutex(name, redsync.WithExpiry(mutexTimeout)) + rs.mutex[name] = mutex + return mutex.Lock() +} + +func (rs *RedisStore) Unlock(name string) error { + mutex, ok := rs.mutex[name] + if ok { + var err error + ok, err = mutex.Unlock() + if ok && err == nil { + return nil + } + } + return errors.New("unlock failed") +} + +func (rs *RedisStore) GetData(name string) ([]byte, error) { + return rs.client.Get(rs.ctx, name).Bytes() +} + +func (rs *RedisStore) SetData(name string, data []byte) error { + return rs.client.Set(rs.ctx, name, data, 0).Err() +} + +func (rs *RedisStore) Close() { + rs.client.Close() +}