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

Support redis lock automatic renewal #55

Merged
merged 5 commits into from
Dec 18, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add LockerOption
baoshi.rao committed Dec 18, 2023
commit df5bb7588f990f2d420b86ba7bb78ed64c144fba
22 changes: 22 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package redislock

import (
"time"

"github.com/go-redsync/redsync/v4"
)

type LockerOption func(*redisLocker)

func WithAutoExtendDuration(duration time.Duration) LockerOption {
return func(locker *redisLocker) {
locker.autoExtendDuration = duration
}
}

// WithRedsyncOptions sets the redsync options.
func WithRedsyncOptions(options ...redsync.Option) LockerOption {
return func(locker *redisLocker) {
locker.options = options
}
}
30 changes: 24 additions & 6 deletions redislock.go
Original file line number Diff line number Diff line change
@@ -25,23 +25,41 @@ var (

// NewRedisLocker provides an implementation of the Locker interface using
// redis for storage.
func NewRedisLocker(r redis.UniversalClient, autoExtendDuration time.Duration, options ...redsync.Option) (gocron.Locker, error) {
func NewRedisLocker(r redis.UniversalClient, options ...redsync.Option) (gocron.Locker, error) {
if err := r.Ping(context.Background()).Err(); err != nil {
return nil, fmt.Errorf("%s: %w", gocron.ErrFailedToConnectToRedis, err)
}
return newLocker(r, autoExtendDuration, options...), nil
return newLocker(r, options...), nil
}

// NewRedisLockerAlways provides an implementation of the Locker interface using
// redis for storage, even if the connection fails.
func NewRedisLockerAlways(r redis.UniversalClient, autoExtendDuration time.Duration, options ...redsync.Option) (gocron.Locker, error) {
return newLocker(r, autoExtendDuration, options...), r.Ping(context.Background()).Err()
func NewRedisLockerAlways(r redis.UniversalClient, options ...redsync.Option) (gocron.Locker, error) {
return newLocker(r, options...), r.Ping(context.Background()).Err()
}

func newLocker(r redis.UniversalClient, autoExtendDuration time.Duration, options ...redsync.Option) gocron.Locker {
func NewRedisLockerWithOptions(r redis.UniversalClient, options ...LockerOption) (gocron.Locker, error) {
if err := r.Ping(context.Background()).Err(); err != nil {
return nil, fmt.Errorf("%s: %w", gocron.ErrFailedToConnectToRedis, err)
}
return newLockerWithOptions(r, options...), nil
}

func newLocker(r redis.UniversalClient, options ...redsync.Option) gocron.Locker {
pool := goredis.NewPool(r)
rs := redsync.New(pool)
return &redisLocker{rs: rs, autoExtendDuration: autoExtendDuration, options: options}
return &redisLocker{rs: rs, options: options}
}

func newLockerWithOptions(r redis.UniversalClient, options ...LockerOption) gocron.Locker {
pool := goredis.NewPool(r)
rs := redsync.New(pool)
l := &redisLocker{rs: rs}
for _, option := range options {
option(l)
}

return l
}

var _ gocron.Locker = (*redisLocker)(nil)
7 changes: 4 additions & 3 deletions redislock_test.go
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ func TestEnableDistributedLocking(t *testing.T) {
}

redisClient := redis.NewClient(&redis.Options{Addr: strings.TrimPrefix(uri, "redis://")})
l, err := NewRedisLocker(redisClient, 0, WithTries(1))
l, err := NewRedisLocker(redisClient, WithTries(1))
require.NoError(t, err)

s1 := gocron.NewScheduler(time.UTC)
@@ -82,7 +82,8 @@ func TestAutoExtend(t *testing.T) {
require.NoError(t, err)

redisClient := redis.NewClient(&redis.Options{Addr: strings.TrimPrefix(uri, "redis://")})
l1, err := NewRedisLocker(redisClient, 0, WithTries(1))
// create lock not auto extend
l1, err := NewRedisLockerWithOptions(redisClient, WithRedsyncOptions(WithTries(1)))
_, err = l1.Lock(ctx, "test1")
require.NoError(t, err)

@@ -94,7 +95,7 @@ func TestAutoExtend(t *testing.T) {
require.NoError(t, err)

// create auto extend lock
l2, err := NewRedisLocker(redisClient, time.Second*2, WithTries(1))
l2, err := NewRedisLockerWithOptions(redisClient, WithAutoExtendDuration(time.Second*2), WithRedsyncOptions(WithTries(1)))
unlocker, err := l2.Lock(ctx, "test2")
require.NoError(t, err)