Documentation
¶
Overview ¶
Example ¶
// Connect to redis. client := redis.NewClient(&redis.Options{ Network: "tcp", Addr: "127.0.0.1:6379", }) defer client.Close() // Create a new lock client. ctx := context.Background() // Try to obtain lock. lock, err := distlock.Obtain(ctx, client, "my-key", 100*time.Millisecond) if err == distlock.ErrNotObtained { fmt.Println("Could not obtain lock!") } else if err != nil { log.Fatalln(err) } // Don't forget to defer Release. defer distlock.Release(ctx, client, lock) fmt.Println("I have a lock!") // Sleep and check the remaining TTL. time.Sleep(50 * time.Millisecond) if ttl, err := distlock.TTL(ctx, client, lock); err != nil { log.Fatalln(err) } else if ttl > 0 { fmt.Println("Yay, I still have my lock!") } // Extend my lock. if err := distlock.Refresh(ctx, client, lock, 100*time.Millisecond); err != nil { log.Fatalln(err) } // Sleep a little longer, then check. time.Sleep(100 * time.Millisecond) if ttl, err := distlock.TTL(ctx, client, lock); err != nil { log.Fatalln(err) } else if ttl == 0 { fmt.Println("Now, my lock has expired!") }
Output: I have a lock! Yay, I still have my lock! Now, my lock has expired!
Index ¶
- Variables
- func Ensure(ctx context.Context, cli RedisClient, lock Lock, ttl time.Duration) error
- func Refresh(ctx context.Context, cli RedisClient, lock Lock, ttl time.Duration) error
- func Release(ctx context.Context, cli RedisClient, lock Lock) error
- func TTL(ctx context.Context, cli RedisClient, lock Lock) (time.Duration, error)
- type Client
- func (c *Client) Ensure(ctx context.Context, lock Lock, ttl time.Duration) error
- func (c *Client) Obtain(ctx context.Context, key string, ttl time.Duration, opts ...Option) (Lock, error)
- func (c *Client) Refresh(ctx context.Context, lock Lock, ttl time.Duration) error
- func (c *Client) Release(ctx context.Context, lock Lock) error
- func (c *Client) TTL(ctx context.Context, lock Lock) (time.Duration, error)
- type Lock
- func (lock Lock) GetKey() string
- func (lock Lock) GetToken() string
- func (lock Lock) Refresh(ctx context.Context, cli RedisClient, ttl time.Duration) error
- func (lock Lock) Release(ctx context.Context, cli RedisClient) error
- func (lock Lock) TTL(ctx context.Context, cli RedisClient) (time.Duration, error)
- type Option
- type RedisClient
- type RetryStrategy
Examples ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var ( // ErrNotObtained is returned when a lock cannot be obtained. ErrNotObtained = errors.New("distlock: not obtained") // ErrLockNotHeld is returned when trying to release an inactive lock. ErrLockNotHeld = errors.New("distlock: lock not held") )
Functions ¶
func Refresh ¶
Refresh extends the lock with a new TTL. May return ErrNotObtained if refresh is unsuccessful.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
func New ¶
func New(client RedisClient) *Client
func (*Client) Obtain ¶
func (c *Client) Obtain(ctx context.Context, key string, ttl time.Duration, opts ...Option) (Lock, error)
Example (CustomDeadline) ¶
client := redis.NewClient(&redis.Options{Network: "tcp", Addr: "127.0.0.1:6379"}) defer client.Close() // Retry every 500ms, for up-to a minute backoff := distlock.LinearBackoff(500 * time.Millisecond) ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Minute)) defer cancel() // Obtain lock with retry + custom deadline lock, err := distlock.Obtain(ctx, client, "my-key", time.Second, distlock.WithRetryStrategy(backoff)) if err == distlock.ErrNotObtained { fmt.Println("Could not obtain lock!") } else if err != nil { log.Fatalln(err) } defer distlock.Release(ctx, client, lock) fmt.Println("I have a lock!")
Output:
Example (Retry) ¶
client := redis.NewClient(&redis.Options{Network: "tcp", Addr: "127.0.0.1:6379"}) defer client.Close() // Retry every 100ms, for up-to 3x backoff := distlock.LimitRetry(distlock.LinearBackoff(100*time.Millisecond), 3) ctx := context.Background() // Obtain lock with retry lock, err := distlock.Obtain(ctx, client, "my-key", time.Second, distlock.WithRetryStrategy(backoff)) if err == distlock.ErrNotObtained { fmt.Println("Could not obtain lock!") } else if err != nil { log.Fatalln(err) } defer distlock.Release(ctx, client, lock) fmt.Println("I have a lock!")
Output:
type Lock ¶
type Lock string
func Obtain ¶
func Obtain(ctx context.Context, cli RedisClient, key string, ttl time.Duration, opts ...Option) (Lock, error)
Obtain tries to obtain a new lock using a key with the given TTL. May return ErrNotObtained if not successful.
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
func WithRetryStrategy ¶
func WithRetryStrategy(strategy RetryStrategy) Option
type RedisClient ¶
type RedisClient interface { SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *redis.BoolCmd EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *redis.Cmd ScriptLoad(ctx context.Context, script string) *redis.StringCmd }
Client is a minimal client interface.
type RetryStrategy ¶
type RetryStrategy interface { // NextBackoff returns the next backoff duration. NextBackoff() time.Duration }
RetryStrategy allows to customise the lock retry strategy.
func ExponentialBackoff ¶
func ExponentialBackoff(min, max time.Duration) RetryStrategy
ExponentialBackoff strategy is an optimization strategy with a retry time of 2**n milliseconds (n means number of times). You can set a minimum and maximum value, the recommended minimum value is not less than 16ms.
func LimitRetry ¶
func LimitRetry(s RetryStrategy, max int) RetryStrategy
LimitRetry limits the number of retries to max attempts.
func LinearBackoff ¶
func LinearBackoff(backoff time.Duration) RetryStrategy
LinearBackoff allows retries regularly with customized intervals
Click to show internal directories.
Click to hide internal directories.