distlock

package
v1.4.2 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package distlock provides Redis-backed distributed locking with two usage modes: fail-hard and fail-silent.

The locker wraps the bsm/redislock library and ensures locks are always released via defer, even if the handler panics. Lock release failures are logged as warnings but do not cause errors.

Basic usage (fail-hard):

locker := distlock.New(redisClient)
err := locker.WithLock(ctx, "resource:123", 30*time.Second, func() error {
    // Exclusive access to resource:123 for 30 seconds
    return updateResource()
})
if err != nil && errors.Is(err, distlock.ErrLockNotObtained) {
    return fmt.Errorf("failed to acquire lock")
}

For background jobs that should silently skip if the lock is unavailable:

err := locker.TryWithLock(ctx, "job:cleanup", 5*time.Minute, cleanupHandler)
// ErrLockNotObtained is swallowed and logged at debug level

Lock TTL is enforced by Redis; the handler should complete well before the TTL expires.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrLockNotObtained = redislock.ErrNotObtained

Functions

This section is empty.

Types

type Locker

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

func New

func New(redisClient redis.UniversalClient) *Locker

func (*Locker) TryWithLock

func (l *Locker) TryWithLock(ctx context.Context, key string, ttl time.Duration, handler func() error) error
Example

ExampleLocker_TryWithLock shows fail-silent locking for background jobs: when the lock is unavailable the handler is skipped without an error. (Not run: requires a Redis server.)

package main

import (
	"context"
	"time"

	"github.com/andyle182810/gframework/distlock"
	"github.com/redis/go-redis/v9"
)

func main() {
	client := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) //nolint:exhaustruct
	locker := distlock.New(client)

	_ = locker.TryWithLock(context.Background(), "jobs:cleanup", 5*time.Minute, func() error {
		// Runs only on the instance that obtained the lock.
		return nil
	})
}

func (*Locker) WithLock

func (l *Locker) WithLock(ctx context.Context, key string, ttl time.Duration, handler func() error) error
Example

ExampleLocker_WithLock shows fail-hard locking: the caller decides what to do when the lock is held elsewhere. (Not run: requires a Redis server.)

package main

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/andyle182810/gframework/distlock"
	"github.com/redis/go-redis/v9"
)

func main() {
	client := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) //nolint:exhaustruct
	locker := distlock.New(client)

	err := locker.WithLock(context.Background(), "resource:123", 30*time.Second, func() error {
		// Exclusive access to resource:123 for up to 30 seconds.
		return nil
	})
	if errors.Is(err, distlock.ErrLockNotObtained) {
		fmt.Println("another instance holds the lock")
	}
}

Jump to

Keyboard shortcuts

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