Documentation
¶
Overview ¶
Package distrlock contains DML (distributed lock manager) implementation (now DMLs based on MySQL and PostgreSQL are supported). Now only manager that uses SQL database (PostgreSQL and MySQL are currently supported) is available. Other implementations (for example, based on Redis) will probably be implemented in the future.
Index ¶
- Constants
- Variables
- func CreateTableSQL(dialect dbkit.Dialect) (string, error)
- func DoExclusively(ctx context.Context, dbConn *sql.DB, dbDialect dbkit.Dialect, key string, ...) error
- func DropTableSQL(dialect dbkit.Dialect) (string, error)
- type DBLock
- func (l *DBLock) Acquire(ctx context.Context, executor SQLExecutor, lockTTL time.Duration) error
- func (l *DBLock) AcquireWithStaticToken(ctx context.Context, executor SQLExecutor, token string, lockTTL time.Duration) error
- func (l *DBLock) DoExclusively(ctx context.Context, dbConn *sql.DB, fn func(ctx context.Context) error, ...) error
- func (l *DBLock) Extend(ctx context.Context, executor SQLExecutor) error
- func (l *DBLock) Release(ctx context.Context, executor SQLExecutor) error
- func (l *DBLock) Token() string
- type DBManager
- type DBManagerOption
- type DoOption
- type Logger
- type SQLExecutor
Examples ¶
Constants ¶
const DefaultTableName = "distributed_locks"
DefaultTableName is a default name for the table that stores distributed locks.
Variables ¶
var ( ErrLockAlreadyAcquired = errors.New("distributed lock already acquired") ErrLockAlreadyReleased = errors.New("distributed lock already released") )
Distributed lock errors.
Functions ¶
func CreateTableSQL ¶ added in v0.4.0
CreateTableSQL returns SQL query for creating a table that stores distributed locks. DefaultTableName is used for the table name. If you need to use a custom table name, construct DBManager and DBLock manually instead.
func DoExclusively ¶ added in v0.4.0
func DoExclusively( ctx context.Context, dbConn *sql.DB, dbDialect dbkit.Dialect, key string, fn func(ctx context.Context) error, options ...DoOption, ) error
DoExclusively acquires distributed lock, calls passed function and releases the lock when the function is finished. It's a ready-to-use helper function that creates a new DBManager, initializes a lock with the given key, and calls DoExclusively on it. DefaultTableName is used for the table name. If you need to use a custom table name, construct DBManager and DBLock manually instead. See DBLock.DoExclusively for more details.
Example ¶
// Setup database connection
db, err := sql.Open("mysql", os.Getenv("MYSQL_DSN"))
if err != nil {
log.Fatal(err)
}
defer db.Close()
ctx := context.Background()
// Create "distributed_locks" table for locks.
createTableSQL, err := distrlock.CreateTableSQL(dbkit.DialectMySQL)
if err != nil {
log.Fatal(err)
}
_, err = db.ExecContext(ctx, createTableSQL)
if err != nil {
log.Fatal(err)
}
// Do some work exclusively.
const lockKey = "test-lock-key-1" // Unique key that will be used to ensure exclusive execution among multiple instances
err = distrlock.DoExclusively(ctx, db, dbkit.DialectMySQL, lockKey, func(ctx context.Context) error {
time.Sleep(10 * time.Second) // Simulate work.
return nil
})
if err != nil {
log.Fatal(err)
}
func DropTableSQL ¶ added in v0.4.0
DropTableSQL returns SQL query for dropping a table that stores distributed locks. DefaultTableName is used for the table name. If you need to use a custom table name, construct DBManager and DBLock manually instead.
Types ¶
type DBLock ¶
DBLock represents a lock object in the database.
func (*DBLock) AcquireWithStaticToken ¶
func (l *DBLock) AcquireWithStaticToken(ctx context.Context, executor SQLExecutor, token string, lockTTL time.Duration) error
AcquireWithStaticToken acquires lock for the key in the database with a static token.
There two use cases for this method:
- When you need to repeatably acquire the same lock preventing other processes from acquiring it at the same time. As an example, you can block an old version of workers before the upgrade and start a new version of them.
- When you need several processes to acquire the same lock.
Please use Acquire instead of this method unless you have a good reason to use it.
func (*DBLock) DoExclusively ¶
func (l *DBLock) DoExclusively( ctx context.Context, dbConn *sql.DB, fn func(ctx context.Context) error, options ...DoOption, ) error
DoExclusively acquires distributed lock, calls passed function and releases the lock when the function is finished. Lock is acquired with a default TTL of 1 minute. TTL can be configured with WithLockTTL option. Additionally, the lock is extended periodically within a separate goroutine. Extension interval can be configured with WithPeriodicExtendInterval option. By default, it's half of the lock TTL. When the function is finished, acquired lock is released. Timeout for lock release can be configured with WithReleaseTimeout option. By default, it's 5 seconds.
func (*DBLock) Extend ¶
func (l *DBLock) Extend(ctx context.Context, executor SQLExecutor) error
Extend resets expiration timeout for already acquired lock. ErrLockAlreadyReleased error will be returned if lock is already released, in this case lock should be acquired again.
type DBManager ¶
type DBManager struct {
// contains filtered or unexported fields
}
DBManager provides management functionality for distributed locks based on the SQL database.
func NewDBManager ¶
func NewDBManager(dialect dbkit.Dialect, options ...DBManagerOption) (*DBManager, error)
NewDBManager creates a new distributed lock manager that uses SQL database as a backend.
Example ¶
// Setup database connection
db, err := sql.Open("mysql", os.Getenv("MYSQL_DSN"))
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Create DBManager
lockManager, err := distrlock.NewDBManager(dbkit.DialectMySQL,
distrlock.WithTableName("my_distributed_locks"))
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// Create table for locks.
_, err = db.ExecContext(ctx, lockManager.CreateTableSQL())
if err != nil {
log.Fatal(err)
}
const lockKey = "test-lock-key-2" // Unique key that will be used to ensure exclusive execution among multiple instances
// Create lock.
lock, err := lockManager.NewLock(ctx, db, lockKey)
if err != nil {
log.Fatal(err)
}
// Acquire lock, do some work and release lock.
const lockTTL = 10 * time.Second
if err = lock.Acquire(ctx, db, lockTTL); err != nil {
log.Fatal(err)
}
defer func() {
if err = lock.Release(ctx, db); err != nil {
log.Fatal(err)
}
}()
time.Sleep(10 * time.Second) // Simulate work
func (*DBManager) CreateTableSQL ¶ added in v0.4.0
CreateTableSQL returns SQL query for creating a table that stores distributed locks.
func (*DBManager) DropTableSQL ¶ added in v0.4.0
DropTableSQL returns SQL query for dropping a table that stores distributed locks.
func (*DBManager) Migrations ¶
Migrations returns set of migrations that must be applied before creating new locks.
type DBManagerOption ¶ added in v0.4.0
type DBManagerOption func(*dbManagerOptions)
DBManagerOption is an option for NewDBManager.
func WithTableName ¶ added in v0.4.0
func WithTableName(tableName string) DBManagerOption
WithTableName sets a custom table name for the table that stores distributed locks.
type DoOption ¶ added in v0.4.0
type DoOption func(*doOptions)
DoOption is an option for DoExclusively method.
func WithLockTTL ¶ added in v0.4.0
WithLockTTL sets TTL for the lock acquired by DoExclusively.
func WithLogger ¶ added in v0.4.0
WithLogger sets logger for DoExclusively.
func WithPeriodicExtendInterval ¶ added in v0.4.0
WithPeriodicExtendInterval sets interval for periodic lock extension.
func WithReleaseTimeout ¶ added in v0.4.0
WithReleaseTimeout sets timeout for lock release.