mirror of https://github.com/pressly/goose.git
99 lines
3.0 KiB
Go
99 lines
3.0 KiB
Go
package lock
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// DefaultLockID is the id used to lock the database for migrations. It is a crc64 hash of the
|
|
// string "goose". This is used to ensure that the lock is unique to goose.
|
|
//
|
|
// crc64.Checksum([]byte("goose"), crc64.MakeTable(crc64.ECMA))
|
|
DefaultLockID int64 = 5887940537704921958
|
|
)
|
|
|
|
// SessionLockerOption is used to configure a SessionLocker.
|
|
type SessionLockerOption interface {
|
|
apply(*sessionLockerConfig) error
|
|
}
|
|
|
|
// WithLockID sets the lock ID to use when locking the database.
|
|
//
|
|
// If WithLockID is not called, the DefaultLockID is used.
|
|
func WithLockID(lockID int64) SessionLockerOption {
|
|
return sessionLockerConfigFunc(func(c *sessionLockerConfig) error {
|
|
c.lockID = lockID
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// WithLockTimeout sets the max duration to wait for the lock to be acquired. The total duration
|
|
// will be the period times the failure threshold.
|
|
//
|
|
// By default, the lock timeout is 300s (5min), where the lock is retried every 5 seconds (period)
|
|
// up to 60 times (failure threshold).
|
|
//
|
|
// The minimum period is 1 second, and the minimum failure threshold is 1.
|
|
func WithLockTimeout(period, failureThreshold uint64) SessionLockerOption {
|
|
return sessionLockerConfigFunc(func(c *sessionLockerConfig) error {
|
|
if period < 1 {
|
|
return errors.New("period must be greater than 0, minimum is 1")
|
|
}
|
|
if failureThreshold < 1 {
|
|
return errors.New("failure threshold must be greater than 0, minimum is 1")
|
|
}
|
|
c.lockProbe = probe{
|
|
intervalDuration: time.Duration(period) * time.Second,
|
|
failureThreshold: failureThreshold,
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// WithUnlockTimeout sets the max duration to wait for the lock to be released. The total duration
|
|
// will be the period times the failure threshold.
|
|
//
|
|
// By default, the lock timeout is 60s, where the lock is retried every 2 seconds (period) up to 30
|
|
// times (failure threshold).
|
|
//
|
|
// The minimum period is 1 second, and the minimum failure threshold is 1.
|
|
func WithUnlockTimeout(period, failureThreshold uint64) SessionLockerOption {
|
|
return sessionLockerConfigFunc(func(c *sessionLockerConfig) error {
|
|
if period < 1 {
|
|
return errors.New("period must be greater than 0, minimum is 1")
|
|
}
|
|
if failureThreshold < 1 {
|
|
return errors.New("failure threshold must be greater than 0, minimum is 1")
|
|
}
|
|
c.unlockProbe = probe{
|
|
intervalDuration: time.Duration(period) * time.Second,
|
|
failureThreshold: failureThreshold,
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
type sessionLockerConfig struct {
|
|
lockID int64
|
|
lockProbe probe
|
|
unlockProbe probe
|
|
}
|
|
|
|
// probe is used to configure how often and how many times to retry a lock or unlock operation. The
|
|
// total timeout will be the period times the failure threshold.
|
|
type probe struct {
|
|
// How often (in seconds) to perform the probe.
|
|
intervalDuration time.Duration
|
|
// Number of times to retry the probe.
|
|
failureThreshold uint64
|
|
}
|
|
|
|
var _ SessionLockerOption = (sessionLockerConfigFunc)(nil)
|
|
|
|
type sessionLockerConfigFunc func(*sessionLockerConfig) error
|
|
|
|
func (f sessionLockerConfigFunc) apply(cfg *sessionLockerConfig) error {
|
|
return f(cfg)
|
|
}
|