lock

package module
v0.0.0-...-0f57fc4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2018 License: MIT Imports: 8 Imported by: 0

README

redis-lock

Build Status GoDoc Go Report Card License

Forked from redis-lock

Simplified distributed locking implementation using Redis.

Different from upstream:

  • Redis-Locker from upstream is not safe for concurrent use. When 02 routines (within a process) access the same token, token is refresh (extend), not locked. Redis-Locker becomes useless, these routines both granted the lock at the same time.

My fork changes the behaviour to be likely as sync.Mutex. Combine with nature of redis-locker, no 02 routines/processes/machines can be granted at the same time.

For use case, please see examples.

Examples

Using locker.Obtain
import (
  "fmt"
  "time"

  "github.com/linxGnu/redis-lock"
  "github.com/go-redis/redis"
)

func main() {
	// Connect to Redis
	client := redis.NewClient(&redis.Options{
		Network:	"tcp",
		Addr:		"127.0.0.1:6379",
	})
	defer client.Close()

	// Obtain a new lock with default settings
	locker, err := lock.Obtain(client, "lock.foo", nil)
	if err != nil {
		fmt.Printf("ERROR: %s\n", err.Error())
		return
	} else if locker == nil {
		fmt.Println("ERROR: could not obtain lock")
		return
	}

	// Don't forget to unlock in the end
	defer locker.Unlock()

	// Run something
	fmt.Println("I have a lock!")
	time.Sleep(200 * time.Millisecond)
}
Error handling
import (
  "fmt"
  "time"

  "github.com/linxGnu/redis-lock"
  "github.com/go-redis/redis"
)

func main() {
	// Connect to Redis
	client := redis.NewClient(&redis.Options{
		Network: "tcp",
		Addr:    "127.0.0.1:6379",
	})
	defer client.Close()

	// Create a new lock with default settings
	locker := dlock.New(client, "lock.foo", nil)

	// warmup connection to redis
	if err := locker.Lock(); err == nil {
		locker.Unlock()
	}

	// Run something
	fmt.Println("I have another lock!")
	time.Sleep(200 * time.Millisecond)
}

Documentation

Full documentation is available on GoDoc

Testing

Simply run:

make

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrLockUnlockFailed     = errors.New("lock unlock failed")
	ErrLockNotObtained      = errors.New("lock not obtained")
	ErrLockDurationExceeded = errors.New("lock duration exceeded")
)

ErrLockNotObtained may be returned by Obtain() and Run() if a lock could not be obtained.

Functions

func Run

func Run(client RedisClient, key string, opts *Options, handler func()) error

Run runs a callback handler with a Redis lock. It may return ErrLockNotObtained if a lock was not successfully acquired.

Types

type Locker

type Locker struct {
	// contains filtered or unexported fields
}

Locker allows (repeated) distributed locking.

func New

func New(client RedisClient, key string, opts *Options) *Locker

New creates a new distributed locker on a given key.

func Obtain

func Obtain(client RedisClient, key string, opts *Options) (locker *Locker, err error)

Obtain is a shortcut for New().Lock(). It may return ErrLockNotObtained if a lock was not successfully acquired.

func (*Locker) Lock

func (l *Locker) Lock() error

Lock applies the lock. If error (lock not obtain or something else), don't call Unlock(). If no error, don't forget to call Unlock() function to release the lock after usage.

func (*Locker) LockWithContext

func (l *Locker) LockWithContext(ctx context.Context) (e error)

LockWithContext is like Lock but allows to pass an additional context which allows cancelling lock attempts prematurely. If error (lock not obtain or something else), don't call Unlock(). If no error, don't forget to call Unlock() function to release the lock after usage.

func (*Locker) Refresh

func (l *Locker) Refresh(ctx context.Context) (err error)

Refresh lock, extend ttl. This function is not thread safe. Only call it when lock is granted.

func (*Locker) Unlock

func (l *Locker) Unlock() error

Unlock releases the lock

type Options

type Options struct {
	// The maximum duration to lock a key for
	// Default: 5s
	LockTimeout time.Duration

	// The number of time the acquisition of a lock will be retried.
	// Default: 0 = do not retry
	RetryCount int

	// RetryDelay is the amount of time to wait between retries.
	// Default: 100ms
	RetryDelay time.Duration

	// TokenPrefix the redis lock key's value will set TokenPrefix + randomToken
	// If we set token prefix as hostname + pid, we can know who get the locker
	TokenPrefix string
}

Options describe the options for the lock

type RedisClient

type RedisClient interface {
	SetNX(key string, value interface{}, expiration time.Duration) *redis.BoolCmd
	Eval(script string, keys []string, args ...interface{}) *redis.Cmd
	EvalSha(sha1 string, keys []string, args ...interface{}) *redis.Cmd
	ScriptExists(scripts ...string) *redis.BoolSliceCmd
	ScriptLoad(script string) *redis.StringCmd
}

RedisClient is a minimal client interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL