locker

package module
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Nov 8, 2021 License: MIT Imports: 8 Imported by: 0

README

go-locker

Build Status Coverage Status Go Reference Go Report Card

Distributed locking using Redis.

Example usage:

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/da440dil/go-locker"
	"github.com/go-redis/redis/v8"
)

func main() {
	client := redis.NewClient(&redis.Options{})
	defer client.Close()

	// Create locker.
	lkr := locker.NewLocker(client)
	ctx := context.Background()
	key := "key"
	err := client.Del(ctx, key).Err()
	requireNoError(err)

	lock := func() {
		// Try to apply lock.
		lr, err := lkr.Lock(ctx, key, time.Second)
		requireNoError(err)
		if !lr.OK() {
			fmt.Printf("Failed to apply lock, retry after %v\n", lr.TTL())
			return
		}
		fmt.Println("Lock applied")

		// Try to release lock.
		defer func() {
			ok, err := lr.Unlock(ctx)
			requireNoError(err)
			if ok {
				fmt.Println("Lock released")
			} else {
				fmt.Println("Failed to release lock")
			}
		}()

		time.Sleep(time.Millisecond * 100) // some code here

		// Optionally try to extend lock.
		r, err := lr.Lock.Lock(ctx, time.Second)
		requireNoError(err)
		if !r.OK() {
			fmt.Printf("Failed to extend lock, retry after %v\n", lr.TTL())
			return
		}
		fmt.Println("Lock extended")
	}

	var wg sync.WaitGroup
	wg.Add(2)
	for i := 0; i < 2; i++ {
		go func() {
			defer wg.Done()
			lock()
		}()
	}
	wg.Wait()
	// Output:
	// Lock applied
	// Failed to apply lock, retry after 999ms
	// Lock extended
	// Lock released
}

func requireNoError(err error) {
	if err != nil {
		panic(err)
	}
}

Documentation

Overview

Package locker provides functions for distributed locking.

Index

Constants

This section is empty.

Variables

View Source
var ErrUnexpectedRedisResponse = errors.New("locker: unexpected redis response")

ErrUnexpectedRedisResponse is the error returned when Redis command returns response of unexpected type.

Functions

This section is empty.

Types

type Lock

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

Lock implements distributed locking.

func (Lock) Lock

func (lock Lock) Lock(ctx context.Context, ttl time.Duration) (Result, error)

Lock applies the lock if it is not already applied, otherwise extends the lock TTL.

func (Lock) Unlock

func (lock Lock) Unlock(ctx context.Context) (bool, error)

Unlock releases the lock.

type LockResult added in v0.3.0

type LockResult struct {
	Lock
	Result
}

LockResult contains new lock and result of applying a lock.

type Locker

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

Locker defines parameters for creating new lock.

func NewLocker

func NewLocker(client RedisClient) *Locker

NewLocker creates new locker.

func (*Locker) Lock

func (locker *Locker) Lock(ctx context.Context, key string, ttl time.Duration) (LockResult, error)

Lock creates and applies new lock.

type RedisClient added in v0.2.0

type RedisClient interface {
	Eval(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd
	EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *redis.Cmd
	ScriptExists(ctx context.Context, hashes ...string) *redis.BoolSliceCmd
	ScriptLoad(ctx context.Context, script string) *redis.StringCmd
}

RedisClient is redis scripter interface.

type Result added in v0.2.0

type Result int64

Result of applying a lock.

func (Result) OK added in v0.2.0

func (r Result) OK() bool

OK is success flag of applying a lock.

func (Result) TTL added in v0.2.0

func (r Result) TTL() time.Duration

TTL of a lock. Makes sense if operation failed, otherwise ttl is less than 0.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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