Skip to content

Commit

Permalink
test & feat: Updated the redis dlock test coverage and added the with…
Browse files Browse the repository at this point in the history
… option builder. (#35)
  • Loading branch information
benz9527 committed May 1, 2024
1 parent 6f69d86 commit f8b4778
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 25 deletions.
76 changes: 51 additions & 25 deletions dlock/redis_dlock.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (dl *redisDLock) Lock() error {
)
for {
if _, err := luaDLockAcquire.Eval(
*dl.ctx.Load(),
*dl.ctx.Load(), // TODO pay attention to the context has been cancelled.
dl.scripterLoader(),
dl.keys,
dl.token, len(dl.token), dl.ttl.Milliseconds(),
Expand Down Expand Up @@ -100,6 +100,7 @@ func (dl *redisDLock) Renewal(newTTL time.Duration) error {
ctx context.Context
cancel context.CancelFunc
)
// TODO pay attention to the context has been cancelled.
ctx, cancel = context.WithTimeout(*dl.ctx.Load(), newTTL)
if ctx != nil && cancel != nil {
if _, err := luaDLockRenewalTTL.Eval(
Expand All @@ -122,7 +123,7 @@ func (dl *redisDLock) TTL() (time.Duration, error) {
return 0, infra.WrapErrorStackWithMessage(ErrDLockNoInit, "fetch dlock ttl failed")
}
res, err := luaDLockLoadTTL.Eval(
*dl.ctx.Load(),
*dl.ctx.Load(), // TODO pay attention to the context has been cancelled.
dl.scripterLoader(),
dl.keys,
dl.token,
Expand All @@ -144,7 +145,7 @@ func (dl *redisDLock) Unlock() error {
return infra.WrapErrorStackWithMessage(ErrDLockNoInit, "attempt to unlock a no init dlock")
}
if _, err := luaDLockRelease.Eval(
*dl.ctx.Load(),
*dl.ctx.Load(), // TODO pay attention to the context has been cancelled.
dl.scripterLoader(),
dl.keys,
dl.token,
Expand Down Expand Up @@ -201,35 +202,60 @@ func (opt *redisDLockOptions) Retry(strategy RetryStrategy) *redisDLockOptions {

func (opt *redisDLockOptions) Build() (DLocker, error) {
if opt.scripterLoader == nil {
return nil, infra.NewErrorStack("[redis-dlock] scripter loader is nil")
return nil, infra.NewErrorStack("dlock scripter loader is nil")
}
if opt.ttl.Milliseconds() <= 0 {
return nil, infra.NewErrorStack("[redis-dlock] lock with zero ms TTL")
return nil, infra.NewErrorStack("dlock with zero ms TTL")
}
if len(opt.keys) <= 0 {
return nil, infra.NewErrorStack("[redis-dlock] lock with zero keys")
}
ctxNotInit := opt.ctxCancel.Load() == nil
if !ctxNotInit {
_, ok := (*opt.ctx.Load()).Deadline()
if !ok {
ctxNotInit = true
}
}
if ctxNotInit {
var (
ctx context.Context
cancel context.CancelFunc
)
ctx, cancel = context.WithTimeout(*opt.ctx.Load(), opt.ttl)
if ctx == nil || cancel == nil {
return nil, infra.NewErrorStack("[redis-dlock] build with nil context or nil context cancel function")
}
opt.ctx.Store(&ctx)
opt.ctxCancel.Store(&cancel)
return nil, infra.NewErrorStack("dlock with zero keys")
}
if opt.strategy == nil {
opt.strategy = NoRetry()
}
var (
ctx context.Context
cancel context.CancelFunc
)
ctx, cancel = context.WithTimeout(*opt.ctx.Load(), opt.ttl)
if ctx == nil || cancel == nil {
return nil, infra.NewErrorStack("dlock build with nil context or nil context cancel function")
}
opt.ctx.Store(&ctx)
opt.ctxCancel.Store(&cancel)
return &redisDLock{redisDLockOptions: opt}, nil
}

type RedisDLockOption func(opt *redisDLockOptions)

func WithRedisDLockTTL(ttl time.Duration) RedisDLockOption {
return func(opt *redisDLockOptions) {
opt.TTL(ttl)
}
}

func WithRedisDLockKeys(keys ...string) RedisDLockOption {
return func(opt *redisDLockOptions) {
opt.Keys(keys...)
}
}

func WithRedisDLockToken(token string) RedisDLockOption {
return func(opt *redisDLockOptions) {
opt.Token(token)
}
}

func WithRedisDLockRetry(strategy RetryStrategy) RedisDLockOption {
return func(opt *redisDLockOptions) {
opt.Retry(strategy)
}
}

func RedisDLock(ctx context.Context, scripter func() redis.Scripter, opts ...RedisDLockOption) (DLocker, error) {
builderOpts := RedisDLockBuilder(ctx, scripter)
for _, o := range opts {
o(builderOpts)
}
return builderOpts.Build()
}
40 changes: 40 additions & 0 deletions dlock/redis_dlock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ func TestRedisDLock_MiniRedis(t *testing.T) {
Token("test1").
Build()
require.NoError(t, err)

err = lock.Unlock()
require.Error(t, err)
_, err = lock.TTL()
require.Error(t, err)
err = lock.Renewal(300 * time.Millisecond)
require.Error(t, err)
err = lock.Renewal(-300 * time.Millisecond)
require.Error(t, err)

err = lock.Lock()
require.NoError(t, err)
ttl, err := lock.TTL()
Expand All @@ -66,6 +76,36 @@ func TestRedisDLock_MiniRedis(t *testing.T) {
t.Log("ttl2", ttl)
err = lock.Unlock()
require.NoError(t, err)

lock, err = RedisDLockBuilder(nil, nil).
Retry(DefaultExponentialBackoffRetry()).
TTL(200*time.Millisecond).
Keys("testKey1_1", "testKey2_1").
Token("test1").
Build()
require.Error(t, err)

lock, err = RedisDLockBuilder(nil,
func() redis.Scripter {
return rclient.Conn()
}).
Retry(DefaultExponentialBackoffRetry()).
TTL(200*time.Nanosecond).
Keys("testKey1_1", "testKey2_1").
Token("test1").
Build()
require.Error(t, err)

lock, err = RedisDLock(nil,
func() redis.Scripter {
return rclient.Conn()
},
WithRedisDLockRetry(DefaultExponentialBackoffRetry()),
WithRedisDLockTTL(200*time.Millisecond),
WithRedisDLockKeys("testKey1", "testKey2"),
WithRedisDLockToken("test1"),
)
require.NoError(t, err)
}

func TestRedisDLock_MiniRedis_DataRace(t *testing.T) {
Expand Down

0 comments on commit f8b4778

Please sign in to comment.