dynamolock

package module
v2.0.0 Latest Latest
Warning

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

Go to latest
Published: Jun 20, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

DynamoDB Lock Client for Go — v2

Build status GoDoc Go Report Card

dynamolock/v2 is a general-purpose distributed locking library for Go, backed by Amazon DynamoDB. It supports both fine-grained and coarse-grained locks: the lock key can be any arbitrary string (up to DynamoDB's key size limit).

It is a Go port of Amazon's original dynamodb-lock-client, written against the AWS SDK for Go v2.

ℹ️ Status: this library is feature-complete and in maintenance mode. Bug fixes and dependency updates are made on a best-effort basis; no new features are planned.


Table of contents


Why dynamolock?

Typical use cases:

  • Mutual exclusion across workers. A distributed system that processes work per customer / per campaign / per entity, and needs to guarantee that only one host operates on each entity at a time.
  • Leader election. Pick a single leader across a fleet of hosts. When the leader dies, another host takes over within a configurable LeaseDuration.
  • Cross-process locks in environments where DynamoDB is already available, avoiding the need to operate a separate locking service (ZooKeeper, etcd, Redis, …).

Installation

go get github.com/arielsrv/dynamolock/v2

Requires Go modules. The minimum Go version is the one declared in go.mod.


Quick start

1. Create the table

The lock table needs a hash (partition) key. You can create it from the AWS console, with Terraform/CloudFormation, or with the convenience helper CreateTableWithContext shown below. Table creation is asynchronous — wait for the table to become ACTIVE before issuing lock calls.

package main

import (
	"context"
	"log"
	"time"

	"github.com/arielsrv/dynamolock/v2"
	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)

func main() {
	ctx := context.Background()

	cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("us-west-2"))
	if err != nil {
		log.Fatal(err)
	}

	c, err := dynamolock.New(
		dynamodb.NewFromConfig(cfg),
		"locks",
		dynamolock.WithLeaseDuration(3*time.Second),
		dynamolock.WithHeartbeatPeriod(1*time.Second),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	log.Println("ensuring table exists")
	if _, err := c.CreateTableWithContext(ctx, "locks",
		dynamolock.WithProvisionedThroughput(&types.ProvisionedThroughput{
			ReadCapacityUnits:  aws.Int64(5),
			WriteCapacityUnits: aws.Int64(5),
		}),
		dynamolock.WithCustomPartitionKeyName("key"),
	); err != nil {
		log.Fatal(err)
	}
}
2. Acquire, use and release a lock
package main

import (
	"context"
	"log"
	"time"

	"github.com/arielsrv/dynamolock/v2"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb"
)

func main() {
	ctx := context.Background()

	cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("us-west-2"))
	if err != nil {
		log.Fatal(err)
	}

	c, err := dynamolock.New(
		dynamodb.NewFromConfig(cfg),
		"locks",
		dynamolock.WithLeaseDuration(3*time.Second),
		dynamolock.WithHeartbeatPeriod(1*time.Second),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	data := []byte("some content a")
	lock, err := c.AcquireLockWithContext(ctx, "spock",
		dynamolock.WithData(data),
		dynamolock.ReplaceData(),
	)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("lock content:", string(lock.Data()))

	// ... do work while holding the lock ...

	log.Println("releasing lock")
	ok, err := c.ReleaseLockWithContext(ctx, lock)
	if err != nil {
		log.Fatal("error releasing lock:", err)
	}
	if !ok {
		log.Fatal("lost lock before release")
	}
	log.Println("done")
}

Features

Automatic heartbeats

When the client is created with WithHeartbeatPeriod(d), a background goroutine periodically refreshes the RecordVersionNumber of every held lock so they don't expire while the process is alive. The lock is released only when you call ReleaseLock / lock.Close() (or when the process exits and the lease eventually expires).

If you prefer to call SendHeartbeat manually, disable the goroutine with DisableHeartbeat() at client construction time.

Reading a lock without acquiring it

You can inspect the current owner and payload of a lock without trying to grab it:

lock, err := c.GetWithContext(ctx, "kirk")
if err != nil {
	// ...
}
fmt.Println(lock.OwnerName(), string(lock.Data()))
Session monitor (lease safety callback)

Long-running critical sections sometimes need to know when the lease is about to expire (for example, because heartbeats have been failing). Pass WithSessionMonitor to AcquireLock and a callback will fire as soon as the lock has less than safeTime remaining:

lock, err := c.AcquireLockWithContext(ctx, "leader",
	dynamolock.WithSessionMonitor(500*time.Millisecond, func() {
		log.Println("lease almost expired, stopping critical work")
	}),
)
Storing arbitrary data with a lock

Use WithData([]byte) (optionally combined with ReplaceData()) when acquiring the lock to attach a payload. Use WithDataAfterRelease([]byte) on release to leave a "tombstone" payload behind. Data is retrieved with lock.Data() or via GetWithContext.

Sort-key partitioned tables

The client supports tables that use a composite primary key (partition + sort). Configure both the client and the table creation:

c, err := dynamolock.New(db, "locks",
	dynamolock.WithPartitionKeyName("key"),
	dynamolock.WithSortKey("scope", "tenant-42"),
)

_, err = c.CreateTableWithContext(ctx, "locks",
	dynamolock.WithCustomPartitionKeyName("key"),
	dynamolock.WithSortKeyName("scope"),
)

All locks created through that client will be scoped to the provided sort-key value.

Context-aware API

Every operation has a *WithContext variant: AcquireLockWithContext, ReleaseLockWithContext, SendHeartbeatWithContext, GetWithContext, CreateTableWithContext, CloseWithContext. Prefer them — they support cancellation and deadlines and are the recommended API in v2. The shorter forms (AcquireLock, ReleaseLock, …) are kept for convenience and use context.Background() internally.


Avoiding clock-skew issues

The client never stores absolute timestamps in DynamoDB — only the relative lease duration is recorded. To expire a lock, AcquireLock reads the current item, remembers its RecordVersionNumber (a GUID), waits up to one lease duration, then re-reads. If the GUID hasn't changed, the previous owner is considered dead and the lock is taken over.

This means two hosts may disagree about wall-clock time and still cooperate safely — only their local monotonic clocks need to be roughly accurate over the lease duration.


Required DynamoDB IAM actions

For full functionality (including CreateTable, tagging and TTL helpers), the IAM role used by the client should be allowed to perform the following actions on the lock table:

  • GetItem
  • PutItem
  • UpdateItem
  • DeleteItem
  • BatchGetItem
  • CreateTable
  • DescribeTable
  • ListTables
  • UpdateTable
  • DeleteTable
  • DescribeTimeToLive
  • UpdateTimeToLive
  • TagResource
  • UntagResource
  • ListTagsOfResource

If you create and manage the table externally, you can restrict the policy to just the item-level actions (GetItem, PutItem, UpdateItem, DeleteItem, BatchGetItem).


Differences from v1

  • Uses AWS SDK for Go v2 (github.com/aws/aws-sdk-go-v2/...) instead of the legacy v1 SDK.
  • All public methods have explicit context.Context variants, and the context-aware forms are the preferred API.
  • The v1 module is retired; new code should depend on github.com/arielsrv/dynamolock/v2.

Example CLI

A small CLI that wraps an arbitrary command in a DynamoDB lock is available under cmd/lock-example. It is also a good reference for setting up the client against DynamoDB Local via the DYNAMODB_ENDPOINT environment variable.

cd cmd/lock-example
make run-dynamodb    # start DynamoDB Local
make run-example     # build & run a sample locked command
make stop-dynamodb   # stop DynamoDB Local

Contributing

Issues and pull requests are welcome at https://github.com/arielsrv/dynamolock. Please run the linters and tests before opening a PR:

make test    # unit + integration tests
make lint    # golangci-lint

This package is covered by the SLA published at https://github.com/arielsrv/public/blob/master/SLA.md.


License

Licensed under the Apache License, Version 2.0.

Documentation

Overview

Package dynamolock provides a simple utility for using DynamoDB's consistent read/write feature to use it for managing distributed locks.

In order to use this package, the client must create a table in DynamoDB, although the client provides a convenience method for creating that table (CreateTable).

Basic usage:

	import (
		"log"

		"github.com/arielsrv/dynamolock/v2"
		"github.com/aws/aws-sdk-go-v2/aws"
		"github.com/aws/aws-sdk-go-v2/config"
		"github.com/aws/aws-sdk-go-v2/service/dynamodb"
		"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
	)

	//---

	cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion("us-west-2"))
	if err != nil {
		log.Fatal(err)
	}
	c, err := dynamolock.New(dynamodb.NewFromConfig(cfg),
		"locks",
		dynamolock.WithLeaseDuration(3*time.Second),
		dynamolock.WithHeartbeatPeriod(1*time.Second),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	log.Println("ensuring table exists")
	c.CreateTable("locks",
		dynamolock.WithProvisionedThroughput(&types.ProvisionedThroughput{
			ReadCapacityUnits:  aws.Int64(5),
			WriteCapacityUnits: aws.Int64(5),
		}),
		dynamolock.WithCustomPartitionKeyName("key"),
	)

 //-- at this point you must wait for DynamoDB to complete the creation.

	data := []byte("some content a")
	lockedItem, err := c.AcquireLock("spock",
		dynamolock.WithData(data),
		dynamolock.ReplaceData(),
	)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("lock content:", string(lockedItem.Data()))
	if got := string(lockedItem.Data()); string(data) != got {
		log.Println("losing information inside lock storage, wanted:", string(data), " got:", got)
	}

	log.Println("cleaning lock")
	success, err := c.ReleaseLock(lockedItem)
	if !success {
		log.Fatal("lost lock before release")
	}
	if err != nil {
		log.Fatal("error releasing lock:", err)
	}
	log.Println("done")

This package is covered by this SLA: https://github.com/arielsrv/public/blob/master/SLA.md

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrSessionMonitorNotSet  = errors.New("session monitor is not set")
	ErrLockAlreadyReleased   = errors.New("lock is already released")
	ErrCannotReleaseNullLock = errors.New("cannot release null lock item")
	ErrOwnerMismatched       = errors.New("lock owner mismatched")
)

Errors related to session manager life-cycle.

View Source
var ErrClientClosed = errors.New("client already closed")

ErrClientClosed reports the client cannot be used because it is already closed.

View Source
var ErrReadOnlyLockHeartbeat = errors.New("cannot send heartbeats to a read-only lock")

ErrReadOnlyLockHeartbeat indicates that the given *Lock is not really a lock, but a read-only copy from a Get call.

Functions

This section is empty.

Types

type AcquireLockOption

type AcquireLockOption func(*acquireLockOptions)

AcquireLockOption allows to change how the lock is actually held by the client.

func FailIfLocked

func FailIfLocked() AcquireLockOption

FailIfLocked will not retry to acquire the lock, instead returning.

func ReplaceData

func ReplaceData() AcquireLockOption

ReplaceData will force the new content to be stored in the key.

func WithAdditionalAttributes

func WithAdditionalAttributes(attr map[string]types.AttributeValue) AcquireLockOption

WithAdditionalAttributes stores some additional attributes with each lock. This can be used to add any arbitrary parameters to each lock row.

func WithAdditionalTimeToWaitForLock

func WithAdditionalTimeToWaitForLock(d time.Duration) AcquireLockOption

WithAdditionalTimeToWaitForLock defines how long to wait in addition to the lease duration (if set to 10 minutes, this will try to acquire a lock for at least 10 minutes before giving up and returning an error).

func WithData

func WithData(b []byte) AcquireLockOption

WithData stores the content into the lock itself.

func WithDeleteLockOnRelease

func WithDeleteLockOnRelease() AcquireLockOption

WithDeleteLockOnRelease defines whether or not the lock should be deleted when Close() is called on the resulting LockItem will force the new content to be stored in the key.

func WithRefreshPeriod

func WithRefreshPeriod(d time.Duration) AcquireLockOption

WithRefreshPeriod defines how long to wait before trying to get the lock again (if set to 10 seconds, for example, it would attempt to do so every 10 seconds).

func WithSessionMonitor

func WithSessionMonitor(safeTime time.Duration, callback func()) AcquireLockOption

WithSessionMonitor registers a callback that is triggered if the lock is about to expire.

The purpose of this construct is to provide two abilities: provide the ability to determine if the lock is about to expire, and run a user-provided callback when the lock is about to expire. The advantage this provides is notification that your lock is about to expire before it is actually expired, and in case of leader election will help in preventing that there are no two leaders present simultaneously.

If due to any reason heartbeating is unsuccessful for a configurable period of time, your lock enters into a phase known as "danger zone." It is during this "danger zone" that the callback will be run.

Bear in mind that the callback may be null. In this case, no callback will be run upon the lock entering the "danger zone"; yet, one can still make use of the Lock.IsAlmostExpired() call. Furthermore, non-null callbacks can only ever be executed once in a lock's lifetime. Independent of whether or not a callback is run, the client will attempt to heartbeat the lock until the lock is released or obtained by someone else.

Consider an example which uses this mechanism for leader election. One way to make use of this SessionMonitor is to register a callback that kills the instance in case the leader's lock enters the danger zone.

The SessionMonitor will not trigger if by the time of its evaluation, the lock is already expired. Therefore, you have to tune the lease, the heartbeat, and the safe time to reduce the likelihood that the lock will be lost at the same time in which the session monitor would be evaluated. A good rule of thumb is to have safeTime to be leaseDuration-(3*heartbeatPeriod).

type Client

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

Client is a dynamoDB based distributed lock client.

func New

func New(dynamoDB DynamoDBClient, tableName string, opts ...ClientOption) (*Client, error)

New creates a new dynamoDB based distributed lock client.

func (*Client) AcquireLock

func (c *Client) AcquireLock(key string, opts ...AcquireLockOption) (*Lock, error)

AcquireLock holds the defined lock.

func (*Client) AcquireLockWithContext

func (c *Client) AcquireLockWithContext(ctx context.Context, key string, opts ...AcquireLockOption) (*Lock, error)

AcquireLockWithContext holds the defined lock. The given context is passed down to the underlying dynamoDB call.

func (*Client) Close

func (c *Client) Close() error

Close releases all of the locks.

func (*Client) CloseWithContext

func (c *Client) CloseWithContext(ctx context.Context) error

CloseWithContext releases all of the locks. The given context is passed down to the underlying dynamoDB calls.

func (*Client) CreateTable

func (c *Client) CreateTable(tableName string, opts ...CreateTableOption) (*dynamodb.CreateTableOutput, error)

CreateTable prepares a DynamoDB table with the right schema for it to be used by this locking library. The table should be set up in advance, because it takes a few minutes for DynamoDB to provision a new instance. Also, if the table already exists, it will return an error.

func (*Client) CreateTableWithContext

func (c *Client) CreateTableWithContext(
	ctx context.Context,
	tableName string,
	opts ...CreateTableOption,
) (*dynamodb.CreateTableOutput, error)

CreateTableWithContext prepares a DynamoDB table with the right schema for it to be used by this locking library. The table should be set up in advance, because it takes a few minutes for DynamoDB to provision a new instance. Also, if the table already exists, it will return an error. The given context is passed down to the underlying dynamoDB call.

func (*Client) Get

func (c *Client) Get(key string) (*Lock, error)

Get loads the given lock, but does not acquire the lock. It returns the metadata currently associated with the given lock. If the client pointer is the one who acquired the lock, it will return the lock, and operations such as releaseLock will work. However, if the client is not the one who acquired the lock, then operations like releaseLock will not work (after calling GetWithContext, the caller should check lockItem.isExpired() to figure out if it currently has the lock.) If the context is canceled, it is going to return the context error on local cache hit.

func (*Client) GetWithContext

func (c *Client) GetWithContext(ctx context.Context, key string) (*Lock, error)

GetWithContext loads the given lock, but does not acquire the lock. It returns the metadata currently associated with the given lock. If the client pointer is the one who acquired the lock, it will return the lock, and operations such as releaseLock will work. However, if the client is not the one who acquired the lock, then operations like releaseLock will not work (after calling GetWithContext, the caller should check lockItem.isExpired() to figure out if it currently has the lock.) If the context is canceled, it is going to return the context error on local cache hit. The given context is passed down to the underlying dynamoDB call.

func (*Client) ReleaseLock

func (c *Client) ReleaseLock(lockItem *Lock, opts ...ReleaseLockOption) (bool, error)

ReleaseLock releases the given lock if the current user still has it, returning true if the lock was successfully released, and false if someone else already stole the lock or a problem happened. Deletes the lock item if it is released and deleteLockItemOnClose is set.

func (*Client) ReleaseLockWithContext

func (c *Client) ReleaseLockWithContext(ctx context.Context, lockItem *Lock, opts ...ReleaseLockOption) (bool, error)

ReleaseLockWithContext releases the given lock if the current user still has it, returning true if the lock was successfully released, and false if someone else already stole the lock or a problem happened. Deletes the lock item if it is released and deleteLockItemOnClose is set.

func (*Client) SendHeartbeat

func (c *Client) SendHeartbeat(lockItem *Lock, opts ...SendHeartbeatOption) error

SendHeartbeat indicates that the given lock is still being worked on. If using WithHeartbeatPeriod > 0 when setting up this object, then this method is unnecessary, because the background thread will be periodically calling it and sending heartbeats. However, if WithHeartbeatPeriod = 0, then this method must be called to instruct DynamoDB that the lock should not be expired.

func (*Client) SendHeartbeatWithContext

func (c *Client) SendHeartbeatWithContext(ctx context.Context, lockItem *Lock, opts ...SendHeartbeatOption) error

SendHeartbeatWithContext indicates that the given lock is still being worked on. If using WithHeartbeatPeriod > 0 when setting up this object, then this method is unnecessary, because the background thread will be periodically calling it and sending heartbeats. However, if WithHeartbeatPeriod = 0, then this method must be called to instruct DynamoDB that the lock should not be expired. The given context is passed down to the underlying dynamoDB call.

type ClientOption

type ClientOption func(*Client)

ClientOption reconfigure the lock client creation.

func DisableHeartbeat

func DisableHeartbeat() ClientOption

DisableHeartbeat disables automatic hearbeats. Use SendHeartbeat to freshen up the lock.

func WithContextLogger

func WithContextLogger(l ContextLogger) ClientOption

WithContextLogger injects a logger into the client, so its internals can be recorded.

func WithHeartbeatPeriod

func WithHeartbeatPeriod(d time.Duration) ClientOption

WithHeartbeatPeriod defines the frequency of the heartbeats. Set to zero to disable it. Heartbeats should have no more than half of the duration of the lease.

func WithLeaseDuration

func WithLeaseDuration(d time.Duration) ClientOption

WithLeaseDuration defines how long should the lease be held.

func WithLogger

func WithLogger(l Logger) ClientOption

WithLogger injects a logger into the client, so its internals can be recorded.

func WithOwnerName

func WithOwnerName(s string) ClientOption

WithOwnerName changes the owner linked to the client, and by consequence to locks.

func WithPartitionKeyName

func WithPartitionKeyName(s string) ClientOption

WithPartitionKeyName defines the key name used for asserting keys uniqueness.

func WithSortKey

func WithSortKey(name string, value string) ClientOption

WithSortKey defines the sort key name and value to use for asserting keys uniqueness. If not set, the sort key will not be used in DynamoDB calls.

type ContextLogger

type ContextLogger interface {
	Println(ctx context.Context, v ...any)
}

ContextLogger defines a logger interface that can be used to pass extra information to the implementation. For example, if you use zap, you may have extra fields you want to add to the log line. You can add those extra fields to the parent context of calls like AcquireLock, and then retrieve them in your implementation of ContextLogger.

type CreateTableOption

type CreateTableOption func(*createDynamoDBTableOptions)

CreateTableOption is an options type for the CreateTable method in the lock client. This allows the user to create a DynamoDB table that is lock client-compatible and specify optional parameters such as the desired throughput and whether or not to use a sort key.

func WithCustomPartitionKeyName

func WithCustomPartitionKeyName(s string) CreateTableOption

WithCustomPartitionKeyName changes the partition key name of the table. If not specified, the default "key" will be used.

func WithProvisionedThroughput

func WithProvisionedThroughput(provisionedThroughput *types.ProvisionedThroughput) CreateTableOption

WithProvisionedThroughput changes the billing mode of DynamoDB and tells DynamoDB to operate in a provisioned throughput mode instead of pay-per-request.

func WithSortKeyName

func WithSortKeyName(s string) CreateTableOption

WithSortKeyName creates the table with a sort key. If not specified, the table will not have a sort key.

func WithTags

func WithTags(tags []types.Tag) CreateTableOption

WithTags changes the tags of the table. If not specified, the table will have empty tags.

type DynamoDBClient

type DynamoDBClient interface {
	GetItem(
		ctx context.Context,
		params *dynamodb.GetItemInput,
		optFns ...func(*dynamodb.Options),
	) (*dynamodb.GetItemOutput, error)
	PutItem(
		ctx context.Context,
		params *dynamodb.PutItemInput,
		optFns ...func(*dynamodb.Options),
	) (*dynamodb.PutItemOutput, error)
	UpdateItem(
		ctx context.Context,
		params *dynamodb.UpdateItemInput,
		optFns ...func(*dynamodb.Options),
	) (*dynamodb.UpdateItemOutput, error)
	DeleteItem(
		ctx context.Context,
		params *dynamodb.DeleteItemInput,
		optFns ...func(*dynamodb.Options),
	) (*dynamodb.DeleteItemOutput, error)
	CreateTable(
		ctx context.Context,
		params *dynamodb.CreateTableInput,
		optFns ...func(*dynamodb.Options),
	) (*dynamodb.CreateTableOutput, error)
}

DynamoDBClient defines the public interface that must be fulfilled for testing doubles.

type Lock

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

Lock item properly speaking.

func (*Lock) AdditionalAttributes

func (l *Lock) AdditionalAttributes() map[string]types.AttributeValue

AdditionalAttributes returns the lock's additional data stored during acquisition.

func (*Lock) Close

func (l *Lock) Close() error

Close releases the lock.

func (*Lock) Data

func (l *Lock) Data() []byte

Data returns the content of the lock, if any is available.

func (*Lock) IsAlmostExpired

func (l *Lock) IsAlmostExpired() (bool, error)

IsAlmostExpired returns whether or not the lock is entering the "danger zone" time period.

It returns if the lock has been released or the lock's lease has entered the "danger zone". It returns false if the lock has not been released and the lock has not yet entered the "danger zone".

func (*Lock) IsExpired

func (l *Lock) IsExpired() bool

IsExpired returns if the lock is expired, released, or neither.

func (*Lock) OwnerName

func (l *Lock) OwnerName() string

OwnerName returns the lock's owner.

type LockNotGrantedError

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

LockNotGrantedError indicates that an AcquireLock call has failed to establish a lock because of its current lifecycle state.

func (*LockNotGrantedError) Error

func (e *LockNotGrantedError) Error() string

func (*LockNotGrantedError) Unwrap

func (e *LockNotGrantedError) Unwrap() error

Unwrap reveals the underlying cause why the lock was not granted.

type Logger

type Logger interface {
	Println(v ...any)
}

Logger defines the minimum desired logger interface for the lock client.

type ReleaseLockOption

type ReleaseLockOption func(*releaseLockOptions)

ReleaseLockOption provides options for releasing a lock when calling the releaseLock() method. This class contains the options that may be configured during the act of releasing a lock.

func WithDataAfterRelease

func WithDataAfterRelease(data []byte) ReleaseLockOption

WithDataAfterRelease is the new data to persist to the lock (only used if deleteLock=false.) If the data is null, then the lock client will keep the data as-is and not change it.

func WithDeleteLock

func WithDeleteLock(deleteLock bool) ReleaseLockOption

WithDeleteLock defines whether or not to delete the lock when releasing it. If set to false, the lock row will continue to be in DynamoDB, but it will be marked as released.

type SendHeartbeatOption

type SendHeartbeatOption func(*sendHeartbeatOptions)

SendHeartbeatOption allows to proceed with Lock content changes in the heartbeat cycle.

func DeleteData

func DeleteData() SendHeartbeatOption

DeleteData removes the Lock data on heartbeat.

func HeartbeatRetries

func HeartbeatRetries(retries int, wait time.Duration) SendHeartbeatOption

HeartbeatRetries helps dealing with transient errors.

func ReplaceHeartbeatData

func ReplaceHeartbeatData(data []byte) SendHeartbeatOption

ReplaceHeartbeatData overrides the content of the Lock in the heartbeat cycle.

func UnsafeMatchOwnerOnly

func UnsafeMatchOwnerOnly() SendHeartbeatOption

UnsafeMatchOwnerOnly helps dealing with network transient errors by relying by expanding the heartbeat scope to include the lock owner. If lock owner is globally unique, then this feature is safe to use.

type TimeoutError

type TimeoutError struct {
	Age time.Duration
}

TimeoutError indicates that the dynamolock gave up acquiring the lock. It holds the length of the attempt that resulted in the error.

func (*TimeoutError) Error

func (e *TimeoutError) Error() string

Directories

Path Synopsis
cmd
lock-example command
Package internal provides a boundary to prevent external packages from using dynamolock's internal interfaces that are subject to change.
Package internal provides a boundary to prevent external packages from using dynamolock's internal interfaces that are subject to change.

Jump to

Keyboard shortcuts

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