lock API

lock

package

API reference for the lock package.

I
interface

Locker

Locker defines the interface for distributed or local locks.

pkg/lock/locker.go:15-25
type Locker interface

Example

// Assuming a RedisLocker implementation
locker := NewRedisLocker(redisClient)
locker.Acquire(ctx, "my-resource", 5*time.Second)

Methods

Acquire
Method

Parameters

key string

Returns

error
func Acquire(...)
TryLock
Method

Parameters

key string

Returns

bool
error
func TryLock(...)
Release
Method

Parameters

key string

Returns

error
func Release(...)
S
struct

InMemoryLocker

InMemoryLocker implements Locker using in-process mutexes.

pkg/lock/memory.go:10-13
type InMemoryLocker struct

Methods

Acquire
Method

Parameters

key string

Returns

error
func (*InMemoryLocker) Acquire(ctx context.Context, key string, ttl time.Duration) error
{
	ticker := time.NewTicker(10 * time.Millisecond)
	defer ticker.Stop()

	for {
		ok, err := l.TryLock(ctx, key, ttl)
		if err != nil {
			return err
		}
		if ok {
			return nil
		}
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-ticker.C:
		}
	}
}
TryLock
Method

Parameters

Returns

bool
error
func (*InMemoryLocker) TryLock(_ context.Context, key string, _ time.Duration) (bool, error)
{
	l.mu.Lock()
	defer l.mu.Unlock()
	if _, exists := l.locks[key]; exists {
		return false, nil
	}
	l.locks[key] = struct{}{}
	return true, nil
}
Release
Method

Parameters

key string

Returns

error
func (*InMemoryLocker) Release(_ context.Context, key string) error
{
	l.mu.Lock()
	defer l.mu.Unlock()
	delete(l.locks, key)
	return nil
}

Fields

Name Type Description
mu sync.Mutex
locks map[string]struct{}
F
function

NewInMemoryLocker

NewInMemoryLocker creates a new in-process Locker.

Returns

pkg/lock/memory.go:16-20
func NewInMemoryLocker() *InMemoryLocker

{
	return &InMemoryLocker{
		locks: make(map[string]struct{}),
	}
}
F
function

TestInMemoryLocker_TryLock

Parameters

pkg/lock/memory_test.go:10-27
func TestInMemoryLocker_TryLock(t *testing.T)

{
	l := NewInMemoryLocker()
	ok, err := l.TryLock(context.Background(), "key1", 0)
	if err != nil {
		t.Fatalf("TryLock failed: %v", err)
	}
	if !ok {
		t.Fatal("expected lock acquired")
	}

	ok, err = l.TryLock(context.Background(), "key1", 0)
	if err != nil {
		t.Fatalf("TryLock second call: %v", err)
	}
	if ok {
		t.Fatal("expected lock not acquired (already held)")
	}
}
F
function

TestInMemoryLocker_Release

Parameters

pkg/lock/memory_test.go:29-45
func TestInMemoryLocker_Release(t *testing.T)

{
	l := NewInMemoryLocker()
	l.TryLock(context.Background(), "k", 0)

	err := l.Release(context.Background(), "k")
	if err != nil {
		t.Fatalf("Release failed: %v", err)
	}

	ok, err := l.TryLock(context.Background(), "k", 0)
	if err != nil {
		t.Fatalf("TryLock after release: %v", err)
	}
	if !ok {
		t.Fatal("expected lock acquired after release")
	}
}
F
function

TestInMemoryLocker_Acquire

Parameters

pkg/lock/memory_test.go:47-68
func TestInMemoryLocker_Acquire(t *testing.T)

{
	l := NewInMemoryLocker()

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		l.TryLock(context.Background(), "shared", 0)
		time.Sleep(50 * time.Millisecond)
		l.Release(context.Background(), "shared")
	}()

	time.Sleep(5 * time.Millisecond)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	err := l.Acquire(ctx, "shared", 0)
	if err != nil {
		t.Fatalf("Acquire failed: %v", err)
	}
	wg.Wait()
}
F
function

TestInMemoryLocker_AcquireContextCancel

Parameters

pkg/lock/memory_test.go:70-81
func TestInMemoryLocker_AcquireContextCancel(t *testing.T)

{
	l := NewInMemoryLocker()
	l.TryLock(context.Background(), "blocked", 0)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
	defer cancel()

	err := l.Acquire(ctx, "blocked", 0)
	if err == nil {
		t.Fatal("expected error from cancelled context")
	}
}
F
function

TestInMemoryLocker_DifferentKeys

Parameters

pkg/lock/memory_test.go:83-90
func TestInMemoryLocker_DifferentKeys(t *testing.T)

{
	l := NewInMemoryLocker()
	ok1, _ := l.TryLock(context.Background(), "a", 0)
	ok2, _ := l.TryLock(context.Background(), "b", 0)
	if !ok1 || !ok2 {
		t.Fatal("different keys should not conflict")
	}
}