Documentation
¶
Overview ¶
Package lease provides a distributed single-holder lease primitive backed by a SQL table. It lets multiple service pods coordinate so that a periodic task runs on exactly one pod at a time, while the other pods skip the tick.
The typical flow is:
l := lease.New(repo)
err := l.WithLease(ctx, "agent-scheduler", 90*time.Second, func(ctx context.Context) error {
return scheduler.checkSchedules(ctx)
})
WithLease acquires the lease, runs fn with a context that is cancelled if the lease is lost, renews the lease at ttl/3 while fn runs, and releases it on exit. If another pod currently holds the lease, WithLease returns nil without running fn.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Lease ¶
type Lease struct {
// contains filtered or unexported fields
}
Lease acquires leases on behalf of a single holder identity.
func New ¶
New returns a Lease that identifies itself as "{hostname}-{pid}", matching the outbox enqueuer's LockOwner convention.
func NewWithHolder ¶
NewWithHolder is like New but uses an explicit holder identity. Intended for tests that need to simulate multiple pods within a single process.
func (*Lease) WithLease ¶
func (l *Lease) WithLease(ctx context.Context, name string, ttl time.Duration, fn func(context.Context) error) error
WithLease runs fn iff the lease `name` can be acquired. While fn runs the lease is renewed at ttl/3 intervals; if renewal fails (the lease was lost), the context passed to fn is cancelled so fn can bail out. On exit the lease is released.
Returns fn's error if fn ran. Returns nil if another pod holds the lease or acquisition errored — these are not treated as caller-visible failures because the tick will simply re-attempt on the next interval.
type Repo ¶
type Repo interface {
// Acquire attempts to claim `name` for `holder`, setting expires_at to now()+ttl. Returns true iff the caller now holds the lease. The claim succeeds when either no row exists for `name`, the existing row has expired, or the existing row is already held by the same `holder` (idempotent re-acquire).
Acquire(ctx context.Context, name, holder string, ttl time.Duration) (bool, error)
// Renew extends expires_at to now()+ttl iff (name, holder) matches. Returns true iff the renewal succeeded. A false return means the lease was lost (expired and taken by someone else, or manually released) and the caller should stop its in-flight work.
Renew(ctx context.Context, name, holder string, ttl time.Duration) (bool, error)
// Release deletes the lease row iff (name, holder) matches. Safe to call even if the caller no longer holds the lease.
Release(ctx context.Context, name, holder string) error
}
Repo abstracts the persistence backend for a task_leases table. MySQL and PostgreSQL each have per-service implementations wrapping sqlc-generated queries.