initial commit

This commit is contained in:
m.zare
2026-04-10 18:25:21 +03:30
commit 77ca6c34a3
263 changed files with 34470 additions and 0 deletions

98
pkg/locker/locker.go Normal file
View File

@@ -0,0 +1,98 @@
package locker
import (
"context"
"fmt"
"time"
"github.com/rs/zerolog"
"github.com/redis/go-redis/v9"
)
type locker struct {
client *redis.Client
logger zerolog.Logger
}
func NewLocker(client *redis.Client, logger zerolog.Logger) Locker {
return &locker{
client: client,
logger: logger,
}
}
func (l locker) Lock(ctx context.Context, id string, ttl time.Duration) (bool, error) {
status := l.client.SetNX(ctx, id, "locked", ttl)
if err := status.Err(); err != nil {
return false, err
}
// Return whether the lock was acquired
return status.Val(), nil
}
func (l locker) Unlock(ctx context.Context, id string) error {
// Delete the lock by its ID
_, err := l.client.Del(ctx, id).Result()
return err
}
// WithLock acquires a lock for a specific vendor, executes the provided function,
// and ensures that the lock is released afterward. If any error occurs, it returns the
// error, preserving the context of the lock operation.
func (l locker) WithLock(
ctx context.Context,
lockKey string,
lockTime time.Duration,
fn func(context.Context) error,
) error {
lg := l.logger.With().
Str("method", "WithLock").
Str("key", lockKey).
Logger()
maxRetries := 5
retryDelay := 10 * time.Millisecond //TODO: Replace with proper logging
var locked bool
var acquireErr error
for attempt := 0; attempt <= maxRetries; attempt++ {
locked, acquireErr = l.Lock(ctx, lockKey, lockTime)
if locked {
lg.Info().Msg("LockAcquired")
break
}
if attempt == maxRetries {
break
}
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(retryDelay):
retryDelay *= 2 // Exponential backoff
}
}
if !locked || acquireErr != nil {
lg.Error().Err(acquireErr).Msg("LockErr")
return NewLockError(lockKey, uint32(maxRetries), acquireErr)
}
fnErr := fn(ctx)
if fnErr != nil {
return fmt.Errorf("failed to execute function for %s due to error %v", lockKey, fnErr)
}
if unlockErr := l.Unlock(ctx, lockKey); unlockErr != nil {
return fmt.Errorf("failed to unlock lock for %s: %v", lockKey, unlockErr)
}
lg.Info().Msg("Unlocked")
return nil
}