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

Add function IsLockedTTLWithLimit checks if the key has been incremen… #53

Open
wants to merge 2 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
60 changes: 42 additions & 18 deletions candiutils/locker.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"time"

"github.com/golangid/candi/options"
"github.com/gomodule/redigo/redis"
)

Expand All @@ -15,39 +16,37 @@ type (
// RedisLocker lock using redis
RedisLocker struct {
pool *redis.Pool
lockeroptions LockerOptions
lockeroptions options.LockerOptions
}

// NoopLocker empty locker
NoopLocker struct{}

// Options for RedisLocker
LockerOptions struct {
Prefix string
TTL time.Duration
}

// Option function type for setting options
LockerOption func(*LockerOptions)
)

// WithPrefix sets the prefix for keys
func WithPrefixLocker(prefix string) LockerOption {
return func(o *LockerOptions) {
func WithPrefixLocker(prefix string) options.LockerOption {
return func(o *options.LockerOptions) {
o.Prefix = prefix
}
}

// WithTTL sets the default TTL for keys
func WithTTLLocker(ttl time.Duration) LockerOption {
return func(o *LockerOptions) {
func WithTTLLocker(ttl time.Duration) options.LockerOption {
return func(o *options.LockerOptions) {
o.TTL = ttl
}
}

// WithLimit sets the limit for keys
func WithLimitLocker(limit int) options.LockerOption {
return func(o *options.LockerOptions) {
o.Limit = limit
}
}

// NewRedisLocker constructor
func NewRedisLocker(pool *redis.Pool, opts ...LockerOption) *RedisLocker {
lockeroptions := LockerOptions{
func NewRedisLocker(pool *redis.Pool, opts ...options.LockerOption) *RedisLocker {
lockeroptions := options.LockerOptions{
Prefix: "LOCKFOR",
TTL: 0,
}
Expand Down Expand Up @@ -104,6 +103,28 @@ func (r *RedisLocker) IsLockedTTL(key string, TTL time.Duration) bool {
return incr > 1
}

func (r *RedisLocker) IsLockedWithOpts(key string, opts ...options.LockerOption) bool {
conn := r.pool.Get()
defer conn.Close()

lockOpt := r.lockeroptions
for _, opt := range opts {
opt(&lockOpt)
}

lockKey := fmt.Sprintf("%s:%s", r.lockeroptions.Prefix, key)
incr, err := redis.Int64(conn.Do("INCR", lockKey))
if err != nil {
return false
}

withLimit := lockOpt.Limit > 1
if lockOpt.TTL > 0 && !(withLimit && incr == 1) {
conn.Do("EXPIRE", lockKey, int(lockOpt.TTL.Seconds()))
}
return incr > int64(lockOpt.Limit)
}

func (r *RedisLocker) HasBeenLocked(key string) bool {
conn := r.pool.Get()
defer conn.Close()
Expand Down Expand Up @@ -215,6 +236,9 @@ func (NoopLocker) IsLocked(string) bool { return false }
// IsLockedTTL method
func (NoopLocker) IsLockedTTL(string, time.Duration) bool { return false }

// IsLockedWithOpts method
func (NoopLocker) IsLockedWithOpts(string, ...options.LockerOption) bool { return false }

// HasBeenLocked method
func (NoopLocker) HasBeenLocked(string) bool { return false }

Expand All @@ -227,10 +251,10 @@ func (NoopLocker) Reset(string) {}
// Lock method
func (NoopLocker) Lock(string, time.Duration) (func(), error) { return func() {}, nil }

func (NoopLocker) Disconnect(context.Context) error { return nil }

// GetPrefix method
func (NoopLocker) GetPrefixLocker() string { return "" }

// GetTTLLocker method
func (NoopLocker) GetTTLLocker() time.Duration { return 0 }

func (NoopLocker) Disconnect(context.Context) error { return nil }
7 changes: 6 additions & 1 deletion codebase/interfaces/locker.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package interfaces

import "time"
import (
"time"

"github.com/golangid/candi/options"
)

type (
// Locker abstraction, lock concurrent process
Locker interface {
IsLocked(key string) bool
IsLockedTTL(key string, ttl time.Duration) bool
IsLockedWithOpts(key string, opts ...options.LockerOption) bool
HasBeenLocked(key string) bool
Unlock(key string)
Reset(key string)
Expand Down
2 changes: 1 addition & 1 deletion mocks/candiutils/HTTPRequest.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions mocks/candiutils/WorkerPool.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mocks/candiutils/cronparser/Schedule.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 19 additions & 1 deletion mocks/codebase/interfaces/Locker.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions mocks/options/LockerOption.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions options/locker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package options

import "time"

type (
// Options for RedisLocker
LockerOptions struct {
Prefix string
TTL time.Duration
Limit int
}

// Option function type for setting options
LockerOption func(*LockerOptions)
)