dlock

package module
v0.5.6 Latest Latest
Warning

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

Go to latest
Published: Mar 8, 2021 License: MIT Imports: 13 Imported by: 2

README

main

dlock is a package for distributed locks. At the moment, available implementations are Kubernetes using the LeaseLock resource, spindle, and Redlock via redsync.

A simple Locker interface is also provided. All lock objects in this package implement this interface.

Usage

LeaseLock

The simplest usage form looks something like:

lock := dlock.NewK8sLock("unique-id", "lock-name")
lock.Lock(context.TODO())
...
lock.Unlock

A sample code is provided for reference. A deployment file is also provided (only tested on GKE). It will deploy two pods that will both try to grab the same lock.

# Deploy to k8s:
$ kubectl create -f k8slock.yaml

# See logs (not the full logs):
$ stern k8slock
main.go:53] [10.28.0.225] attempt to grab lock for a minute...
main.go:53] [10.28.4.52] attempt to grab lock for a minute...
main.go:47] [10.28.4.52] lock acquired by 10.28.4.52
main.go:57] [10.28.4.52] got the lock within that minute!
main.go:64] [10.28.4.52] now, let's attempt to grab the lock until termination
main.go:47] [10.28.4.52] lock acquired by 10.28.4.52
main.go:61] [10.28.0.225] we didn't get the lock within that minute
main.go:64] [10.28.0.225] now, let's attempt to grab the lock until termination
main.go:73] [10.28.0.225] stopping...
main.go:78] [10.28.0.225] we didn't get the lock in the end
main.go:73] [10.28.4.52] stopping...
main.go:75] [10.28.4.52] got the lock in the end

# Cleanup:
$ kubectl delete -f k8slock.yaml

spindle

This implementation is a wrapper to the spindle distributed locking library by providing a blocking Lock(...) / Unlock() function pair. This is probably useful if you are already using Cloud Spanner.

The basic usage will look something like:

ctx := context.Background()
db, _ := spanner.NewClient(ctx, "your/database")
defer db.Close()

lock := dlock.NewSpindleLock(&dlock.SpindleLockOptions{
  Client:   db,
  Table:    "testlease",
  Name:     "dlock",
  Duration: 1000,
})

start := time.Now()
lock.Lock(ctx)
log.Printf("lock acquired after %v, do protected work...", time.Since(start))
time.Sleep(time.Second * 5)
lock.Unlock()

Redis

The Redis implementation is basically a wrapper to the brilliant redsync package, with additional utility functions for working with Redis connection pools. It's also implemented in a way to follow the Locker interface.

To use with a single Redis host, no password, use defaults:

lock := dlock.NewRedisLock("testredislock", dlock.WithHost("1.2.3.4"))
lock.Lock(context.Background())
...
lock.Unlock()

To use with a single Redis host, with password, use defaults:

pool := dlock.NewRedisPool("1.2.3.4", dlock.WithPassword("secret-pass"))
lock := dlock.NewRedisLock("testredislock", dlock.WithPools([]*redis.Pool{pool}))
lock.Lock(context.Background())
...
lock.Unlock()

You can check out the test file and the sample code for usage reference. You can run the sample code in separate terminals simultaneously and one process should be able to grab the Redis lock.


Todo

PR's are welcome.

  • LeaseLock (k8s)
  • spindle
  • etcd
  • Zookeeper
  • Consul
  • Redis
  • Add CI

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewRedisLock

func NewRedisLock(name string, opts ...RedisLockOption) *rlock

NewRedisLock creates an object that can be used to acquire/release a lock using Redis. This is built on top of redsync with the addition of context and implementing the Locker interface.

func NewRedisPool

func NewRedisPool(host string, opts ...RedisPoolOption) *redis.Pool

RedisPool returns a connection pool for Redis.

Types

type K8sLock

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

func NewK8sLock

func NewK8sLock(id, name string, opts ...K8sLockOption) *K8sLock

NewK8sLock returns an object that can be used to acquire/release a lock using k8s' LeaseLock resource object. id is the locker's unique identity displayed as the HOLDER when you do kubectl get lease. name is the LeaseLock resource name. When not set, it will use the default namespace.

func (*K8sLock) IsLeader added in v0.4.0

func (l *K8sLock) IsLeader() bool

func (*K8sLock) Lock

func (l *K8sLock) Lock(ctx context.Context) error

Lock attempts to acquire a k8s lock using LeaseLock. This call will unblock/return when lock is acquired or when ctx expires or is cancelled.

func (*K8sLock) Unlock

func (l *K8sLock) Unlock() error

Unlock releases the lock object.

type K8sLockOption

type K8sLockOption interface {
	Apply(*K8sLock)
}

func WithK8sClient

func WithK8sClient(c *kubernetes.Clientset) K8sLockOption

WithK8sClient provides an option to set a k8s client object.

func WithLeaseDuration

func WithLeaseDuration(v time.Duration) K8sLockOption

WithLeaseDuration provides an option to set the lease duration.

func WithNamespace

func WithNamespace(v string) K8sLockOption

WithNamespace provides an option to set the namespace value.

func WithNewLeaderCallback

func WithNewLeaderCallback(v func(string)) K8sLockOption

WithNewLeaderCallback provides an option to set a callback when new lock is acquired.

func WithRenewDeadline

func WithRenewDeadline(v time.Duration) K8sLockOption

WithRenewDeadline provides an option to set the renew deadline.

func WithRetryPeriod

func WithRetryPeriod(v time.Duration) K8sLockOption

WithRetryPeriod provides an option to set the renew deadline.

func WithStartCallback

func WithStartCallback(v func(context.Context)) K8sLockOption

WithStartCallback provides an option to set a callback after we acquired the new lock.

type Locker

type Locker interface {
	Lock(ctx context.Context) error
	Unlock() error
}

type RedisLockOption

type RedisLockOption interface {
	Apply(*rlock)
}

func WithExtendAfter

func WithExtendAfter(v time.Duration) RedisLockOption

WithExtendAfter provides an option to set the duration before extending the lock.

func WithHost

func WithHost(v string) RedisLockOption

WithHost provides an option to set a single Redis host for the lock.

func WithHosts

func WithHosts(v []string) RedisLockOption

WithHosts provides an option to set a list of Redis hosts for the lock.

func WithPools

func WithPools(v []*redis.Pool) RedisLockOption

WithPools provides an option to set a list of Redis pools for the lock.

func WithRedsyncOptions added in v0.2.0

func WithRedsyncOptions(v []redsync.Option) RedisLockOption

WithRedsyncOptions provides an option to set additional options to the underlying redsync Mutex.

type RedisPoolOption

type RedisPoolOption interface {
	Apply(*rpool)
}

func WithPassword

func WithPassword(v string) RedisPoolOption

WithPassword provides an option to set a password to a Redis pool.

func WithTimeout

func WithTimeout(v time.Duration) RedisPoolOption

WithTimeout provides an option to set a timeout to a Redis pool.

type SpindleLock added in v0.5.0

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

func NewSpindleLock added in v0.5.0

func NewSpindleLock(opts *SpindleLockOptions) *SpindleLock

func (*SpindleLock) Lock added in v0.5.0

func (l *SpindleLock) Lock(ctx context.Context) error

func (*SpindleLock) Unlock added in v0.5.0

func (l *SpindleLock) Unlock() error

type SpindleLockOptions added in v0.5.0

type SpindleLockOptions struct {
	Client   *spanner.Client // Spanner client
	Table    string          // Spanner table name
	Name     string          // lock name
	Id       string          // optional, generated if empty
	Duration int64           // optional, will use spindle's default
	Logger   *log.Logger     // pass to spindle
}

Directories

Path Synopsis
examples
redislock Module

Jump to

Keyboard shortcuts

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