glock

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2025 License: Apache-2.0 Imports: 11 Imported by: 0

README

Golang Distributed Lock

Go Report Card License GoDoc

A Golang Distributed Lock package with multiple backends, supporting DynamoDB, Redis, etcd, Consul, ZooKeeper, Hazelcast, MongoDB, and PostgreSQL. Built for high availability, fault tolerance, and performance, with OpenTelemetry support for tracing and metrics.

Features 🚀

✅ Supports multiple storage backends
✅ Provides Acquire, Release, Renew, and AcquireWithRetry functions
Atomic operations for safe concurrency control
✅ Implements OpenTelemetry for tracing and metrics
✅ Uses functional options pattern for extensibility

Installation 📦

go get github.com/companyinfo/glock

Usage 🛠️

Initialize the Lock Manager

Each backend requires specific configuration. Below is an example.

Redis
package main

import (
    "context"
    "fmt"

    "github.com/go-logr/logr"
    "github.com/go-redis/redis/v8"

    "github.com/companyinfo/glock"
    "github.com/companyinfo/glock/redislock"
)

func main() {
    logger := logr.Logger{}.V(1).WithName("distributed-lock")
    redisClient := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
    lock := redislock.New(redisClient, glock.WithLogger(logger))

    if err := lock.Acquire(context.Background(), "prod:lock:object:12", 10); err != nil {
        fmt.Println("Failed to acquire lock")
    }

    defer lock.Release(context.Background(), "prod:lock:object:12")
}

Supported Backends 🔌

Backend Implementation
DynamoDB dynamolock.New
Redis redislock.New
etcd etcdlock.New
Consul consullock.New
ZooKeeper zookeeperlock.New
Hazelcast hazelcastlock.New
MongoDB mongolock.New
PostgreSQL postgreslock.New

OpenTelemetry Integration 📊

This package supports OpenTelemetry for distributed tracing and metrics.

Metrics Supported
  • lock_acquire_total
  • lock_acquire_latency_seconds
  • lock_release_total
  • lock_release_latency_seconds
  • lock_renew_total
  • lock_renew_latency_seconds

License 📜

This project is licensed under the MIT License. See LICENSE for details.


Documentation

Overview

Package glock provides a flexible and configurable distributed locking mechanism that supports multiple backends such as DynamoDB, MongoDB, PostgreSQL, etc. It allows users to acquire, renew, and release locks in a distributed system while ensuring consistency and preventing race conditions.

Index

Constants

View Source
const (
	// ActionAcquire represents the action of attempting to acquire a lock.
	ActionAcquire = "acquire"
	// ActionRelease represents the action of releasing a previously acquired lock.
	ActionRelease = "release"
	// ActionRenew represents the action of extending the expiration time of a lock.
	ActionRenew = "renew"
	// ActionAcquiredSuccessfully indicates that a lock was successfully acquired.
	ActionAcquiredSuccessfully = "acquired"
	// ActionReleasedSuccessfully indicates that a lock was successfully released.
	ActionReleasedSuccessfully = "released"
	// ActionRenewedSuccessfully indicates that a lock was successfully renewed.
	ActionRenewedSuccessfully = "renewed"
)
View Source
const (
	// BackendConsul represents Consul as a distributed locking backend.
	BackendConsul = "consul"
	// BackendEtcd represents etcd as a distributed locking backend.
	BackendEtcd = "etcd"
	// BackendDynamoDB represents AWS DynamoDB as a distributed locking backend.
	BackendDynamoDB = "dynamodb"
	// BackendHazelcast represents Hazelcast as a distributed locking backend.
	BackendHazelcast = "hazelcast"
	// BackendMongoDB represents MongoDB as a distributed locking backend.
	BackendMongoDB = "mongodb"
	// BackendRedis represents Redis as a distributed locking backend.
	BackendRedis = "redis"
	// BackendZooKeeper represents Apache ZooKeeper as a distributed locking backend.
	BackendZooKeeper = "zookeeper"
	// BackendPostgres represents PostgreSQL as a distributed locking backend.
	BackendPostgres = "postgres"
)
View Source
const (
	// Name represents the default name of the distributed lock package.
	Name = "distributed_lock"
	// DefaultLogLevel defines the default logging level (0 usually means "info" or "debug").
	DefaultLogLevel = 0
	// DefaultLoggerName specifies the default logger name for logging events related to distributed locks.
	DefaultLoggerName = "distributed_lock"
	// DefaultTable defines the default table name for storing locks in relational databases like PostgreSQL.
	DefaultTable = "distributed_lock"
	// DefaultTTLField specifies the field name used to store the lock expiration time.
	DefaultTTLField = "expiration_time"
	// DefaultLockField represents the field name used to store the lock identifier.
	DefaultLockField = "lock_id"
	// DefaultMap defines the default map name used in Hazelcast for storing locks.
	DefaultMap = "distributed_lock"
	// DefaultDatabase specifies the default database name used in MongoDB or other NoSQL backends.
	DefaultDatabase = "distributed_lock"
	// DefaultCollection defines the default collection name for storing locks in MongoDB.
	DefaultCollection = "locks"
)

Variables

View Source
var (
	// ErrLockIsHeld lock is already held by another process.
	ErrLockIsHeld = errors.New("lock is already held by another process")
	// ErrLockIsNotHeld lock was not held or already released.
	ErrLockIsNotHeld = errors.New("lock was not held or already released")
	// ErrLockTimeout lock acquisition timed out.
	ErrLockTimeout = errors.New("lock acquisition timed out")
)

Functions

func GetLogger

func GetLogger() logr.Logger

GetLogger returns the global Logger instance.

func GetTracer

func GetTracer() trace.Tracer

GetTracer returns the global Tracer instance.

func HandleError

func HandleError(
	ctx context.Context,
	span trace.Span,
	err error,
	backend, action, msg, lockID string) error

HandleError logs, records metrics, and returns a formatted error.

func InitializeLogger

func InitializeLogger(l logr.Logger)

InitializeLogger sets up logger with a user-defined or default logger.

func InitializeMetrics

func InitializeMetrics(mp metric.MeterProvider)

InitializeMetrics ensures metrics are only initialized once.

func InitializeTracing

func InitializeTracing(tp trace.TracerProvider)

InitializeTracing sets up tracing with a user-defined or default tracer provider.

func RecordStart

func RecordStart(ctx context.Context, backend, action, lockID string) (context.Context, trace.Span)

RecordStart starts a new tracing span for a given operation.

func RecordSuccess

func RecordSuccess(
	ctx context.Context,
	span trace.Span,
	startTime time.Time,
	action, backend, lockID string)

RecordSuccess logs and records success metrics.

Types

type Lock

type Lock interface {
	// Acquire attempts to lock a resource identified by lockID for the specified TTL (in seconds).
	// Returns an error if the lock is already held or on failure.
	Acquire(ctx context.Context, lockID string, ttl int64) error

	// AcquireWithRetry attempts to lock a resource identified by lockID for the specified TTL (in seconds).
	// Returns an error if the lock is already held or on failure after a retry attempt.
	AcquireWithRetry(ctx context.Context, lockID string, ttl int64, retryInterval time.Duration, maxRetries int) error

	// Release unlocks a resource identified by lockID.
	// Returns an error if releasing the lock fails.
	Release(ctx context.Context, lockID string) error

	// Renew extends the TTL of an existing lock.
	// Returns an error if renewing the lock fails.
	Renew(ctx context.Context, lockID string, ttl int64) error
}

Lock defines the interface for distributed locking. Implementations must provide Acquire, AcquireWithRetry, and Release methods.

type LockConfig

type LockConfig struct {
	Table      string
	TTLField   string
	LockField  string
	Map        string
	Database   string
	Collection string
}

LockConfig A struct holding configuration settings such as logger, database/table names, and OpenTelemetry tracer/meter.

func DefaultConfig

func DefaultConfig() *LockConfig

DefaultConfig returns a LockConfig with default values, including: - A default logger with predefined log level and name. - An OpenTelemetry tracer and meter for distributed tracing and metrics.

type LockLogger

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

LockLogger holds the global logger.

type LockMetrics

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

LockMetrics holds common lock-related metrics.

func GetMetrics

func GetMetrics() *LockMetrics

GetMetrics returns the global LockMetrics instance.

type LockTracer

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

LockTracer holds the global tracer.

type MockLock

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

MockLock is a mock implementation of the Lock interface for testing.

func NewMockLock

func NewMockLock() *MockLock

NewMockLock creates a new instance of MockLock.

func (*MockLock) Acquire

func (m *MockLock) Acquire(_ context.Context, lockID string, ttl int64) error

Acquire simulates acquiring a lock.

func (*MockLock) AcquireWithRetry

func (m *MockLock) AcquireWithRetry(
	ctx context.Context,
	lockID string,
	ttl int64,
	retryInterval time.Duration,
	maxRetries int) error

AcquireWithRetry mocks the acquisition of a lock with retries.

func (*MockLock) Release

func (m *MockLock) Release(_ context.Context, lockID string) error

Release simulates releasing a lock.

func (*MockLock) Renew

func (m *MockLock) Renew(_ context.Context, lockID string, ttl int64) error

Renew simulates renewing a lock.

type OptionFunc

type OptionFunc func(*LockConfig)

OptionFunc A function type used to apply custom configurations to LockConfig.

func WithCollection

func WithCollection(name string) OptionFunc

WithCollection sets the collection name for NoSQL storage backends like MongoDB.

func WithDatabase

func WithDatabase(name string) OptionFunc

WithDatabase sets the database name for storage backends that require a database name (e.g., MongoDB, PostgreSQL).

func WithLockField

func WithLockField(name string) OptionFunc

WithLockField sets the lock identifier field name in the storage backend. This field uniquely identifies a lock record.

func WithLogger

func WithLogger(logger logr.Logger) OptionFunc

WithLogger sets a custom logger in LockConfig. This allows users to integrate their own logging implementation.

func WithMapName

func WithMapName(name string) OptionFunc

WithMapName sets the map name for storage backends that use key-value maps (e.g., Hazelcast).

func WithMeterProvider

func WithMeterProvider(mp metric.MeterProvider) OptionFunc

WithMeterProvider sets a custom OpenTelemetry meter provider for capturing metrics. If not set, the default OpenTelemetry meter is used.

func WithTTLField

func WithTTLField(name string) OptionFunc

WithTTLField sets the TTL (expiration) field name in the storage backend. This field is used to track lock expiration.

func WithTable

func WithTable(name string) OptionFunc

WithTable sets the table name for storage backends that use tables (e.g., DynamoDB, PostgreSQL).

func WithTracerProvider

func WithTracerProvider(tp trace.TracerProvider) OptionFunc

WithTracerProvider sets a custom OpenTelemetry tracer provider for distributed tracing. If not set, the default OpenTelemetry tracer is used.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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