Documentation
¶
Overview ¶
Package lease supplies typed, time-limited ownership with explicit loss and cleanup.
Index ¶
- Constants
- Variables
- func Module(name foundation.ProviderID, key foundation.Key[*Manager], config Config, ...) foundation.Module
- func ValidateDuration(ttl time.Duration) error
- func ValidateOperation(ctx context.Context, key Key, owner Owner, ttl time.Duration) error
- type Backend
- type Config
- type Declaration
- type ForceBackend
- type Guard
- type Key
- type Leases
- func (l Leases[K]) Acquire(ctx context.Context, key K, ttl, wait time.Duration) (*Guard, bool, error)
- func (l Leases[K]) Export(g *Guard) (Token[K], error)
- func (l Leases[K]) ForceRelease(ctx context.Context, key K) (bool, error)
- func (l Leases[K]) Restore(ctx context.Context, token Token[K]) (*Guard, error)
- func (l Leases[K]) TryAcquire(ctx context.Context, key K, ttl time.Duration) (*Guard, bool, error)
- func (l Leases[K]) With(ctx context.Context, key K, ttl, wait time.Duration, ...) (bool, error)
- func (l Leases[K]) WithProof(ctx context.Context, key K, ttl, wait time.Duration, ...) (bool, error)
- type Manager
- func (m *Manager) BorrowedBackend() Backend
- func (m *Manager) Close(ctx context.Context) error
- func (m *Manager) Done() <-chan struct{}
- func (m *Manager) Namespace() keyspace.Namespace
- func (m *Manager) PollInterval() time.Duration
- func (m *Manager) Stats() Stats
- func (m *Manager) ValidateScope(ttl, wait time.Duration) error
- type Name
- type Owner
- type Proof
- type Semaphore
- type SemaphoreDeclaration
- type Stats
- type Token
- type TransferBackend
Constants ¶
const ( MinDuration = 10 * time.Millisecond MaxDuration = 24 * time.Hour )
Duration bounds keep expiry finite and leave room for client validity margins.
const KeyFeature keyspace.Feature = "lease"
KeyFeature is the physical address family owned by this adapter.
const MaxSemaphoreSlots = 1024
MaxSemaphoreSlots bounds the leases one semaphore resource can hold.
const OwnerBytes = 32
Variables ¶
var ErrExported = safeerror.Sentinel(fault.Closed, "lease ownership exported")
ErrExported marks a guard whose ownership was handed to another process.
var ErrLost = safeerror.Sentinel(fault.Conflict, "lease ownership lost")
ErrLost means ownership could no longer be confirmed within its validity window.
var ErrReleased = safeerror.Sentinel(fault.Closed, "lease released")
ErrReleased marks explicit release of a guard's work context.
Functions ¶
func Module ¶
func Module(name foundation.ProviderID, key foundation.Key[*Manager], config Config, requires []foundation.ProviderID, backend func(foundation.Resolver) (Backend, error)) foundation.Module
Module builds one manager per application. requires identifies the provider(s) owning the borrowed backend, ensuring leases drain before those adapters close.
func ValidateDuration ¶
ValidateDuration rejects durations outside MinDuration through MaxDuration with fault.Invalid.
Types ¶
type Backend ¶
type Backend interface {
// LeaseAcquire sets an absent key to owner for ttl and reports whether ownership was acquired.
LeaseAcquire(context.Context, Key, Owner, time.Duration) (bool, error)
// LeaseRenew extends ttl only while owner still owns an unexpired key.
LeaseRenew(context.Context, Key, Owner, time.Duration) (bool, error)
// LeaseRelease removes key only while owner still owns it and reports whether it was removed.
LeaseRelease(context.Context, Key, Owner) (bool, error)
}
Backend atomically acquires an absent key, or renews/releases only its current owner. Expired ownership is absent. Errors must never be treated as contention. Implementations must honor cancellation, perform no implicit mutation retries, and bound stored owner reads. TTL begins when the authority accepts a mutation. Renew cannot recreate expired ownership. Callers own adapter lifecycle.
type Config ¶
type Config struct {
Namespace keyspace.Namespace
MaxActive, MaxDeclarations, MaxKeyBytes int
OperationTimeout, MaxWait, PollInterval time.Duration
}
Config bounds all acquisitions, waiters, live guards and owned callbacks in one manager. A scoped callback retains its slot until it actually exits, even after ownership loss. OperationTimeout also bounds each independent cleanup attempt.
func DefaultConfig ¶
DefaultConfig returns the default manager bounds for namespace.
type Declaration ¶
type Declaration[K any] struct { // contains filtered or unexported fields }
Declaration retains the resource key type. Reuse one declared value per family.
func Define ¶
func Define[K any](name Name, codec keyspace.Codec[K]) Declaration[K]
Define constructs a typed lease family with the supplied key codec.
func (Declaration[K]) Bind ¶
func (d Declaration[K]) Bind(m *Manager) (Leases[K], error)
Bind rejects a distinct declaration with the same family name, even for the same K.
func (Declaration[K]) Name ¶
func (d Declaration[K]) Name() Name
Name returns the family name, or an empty name for a zero declaration.
func (Declaration[K]) Validate ¶
func (d Declaration[K]) Validate() error
Validate checks the family name and key codec; a zero declaration is invalid.
type ForceBackend ¶
type ForceBackend interface {
// LeaseForceRelease removes key regardless of its owner and reports whether it existed.
LeaseForceRelease(context.Context, Key) (bool, error)
}
ForceBackend is an optional administrative capability that removes a lease address regardless of its owner, including metadata that ordinary operations reject as corrupt (for example a Redis lease key without expiry). It is never used implicitly; ordinary acquisition, renewal and release stay owner-checked.
type Guard ¶
type Guard struct {
// contains filtered or unexported fields
}
Guard represents one ownership interval. It has no finalizer: release it explicitly, cancel its parent, or close its manager. Expiry also owns cleanup. Context cancellation is cooperative; external writes require resource fencing when stale-process exclusion is necessary. Guards cannot be copied usefully.
func (*Guard) Context ¶
Context preserves caller values and is canceled on release, expiry, renewal failure, caller cancellation or manager shutdown. A zero guard returns nil.
func (*Guard) Done ¶
func (g *Guard) Done() <-chan struct{}
Done closes after renewal work and owner cleanup finish. A nil guard returns nil.
func (*Guard) Err ¶
Err rechecks validity synchronously, including after a process scheduling pause.
func (*Guard) Proof ¶
Proof exposes this guard's ownership to an adapter, without allowing callers to construct an arbitrary key/token pair. Ordinary domain work needs Context.
func (*Guard) Release ¶
Release cancels protected work and waits for one owner-conditional cleanup. Caller cancellation only stops waiting. Repeated/concurrent releases share the same attempt and result. Ownership loss remains available from Err separately.
type Key ¶
type Key struct {
// contains filtered or unexported fields
}
Key is an opaque adapter address. It cannot be confused with a cache entry.
type Leases ¶
type Leases[K any] struct { // contains filtered or unexported fields }
Leases only accepts its declaration's concrete resource key type.
func (Leases[K]) Acquire ¶
func (l Leases[K]) Acquire(ctx context.Context, key K, ttl, wait time.Duration) (*Guard, bool, error)
Acquire waits only on confirmed contention, up to wait. A zero wait tries once. Wait expiration returns context.DeadlineExceeded; backend uncertainty is never retried. The guard's context retains the original caller lifetime, not the acquisition timeout.
func (Leases[K]) Export ¶
Export hands a live explicit guard's ownership out of this process. The guard stops renewing and ends with ErrExported WITHOUT releasing the authority key; the importing process must Restore the token before the lease's TTL expires and becomes responsible for releasing it. The token is single-use (see Restore). The guard must belong to l's family.
func (Leases[K]) ForceRelease ¶
ForceRelease administratively removes key's lease whatever its owner. Use it to repair corrupt or non-expiring lease metadata, or to break ownership after confirming the owning process is gone. It reports whether a lease existed. A current holder is not notified: it loses ownership at its next renewal or protected write, so resources that need stale-process exclusion still need their own fencing. The backend must implement ForceBackend.
func (Leases[K]) Restore ¶
Restore resumes ownership from an exported token. Tokens are single-use: the authority atomically replaces the token's owner secret with a fresh one and renews the lease, so restoring the same token again (a retried job or a redelivered message) returns ErrLost instead of creating a second holder. It returns an explicit guard (no automatic heartbeat) under the same rules as Acquire. A token whose lease expired, was released, was replaced or was already restored returns ErrLost. The backend must implement TransferBackend.
func (Leases[K]) TryAcquire ¶
TryAcquire attempts once. Contention returns (nil,false,nil). A returned guard owns its finite lifetime and must be released. It renews only when Renew is called.
func (Leases[K]) With ¶
func (l Leases[K]) With(ctx context.Context, key K, ttl, wait time.Duration, fn func(context.Context) error) (bool, error)
With runs an owned callback while automatically renewing. It returns whether the callback ran, plus callback/loss/cleanup errors. Cancellation or renewal uncertainty cancels the supplied context; return promptly when it is canceled. With always waits for the callback's actual exit before releasing its slot.
func (Leases[K]) WithProof ¶
func (l Leases[K]) WithProof(ctx context.Context, key K, ttl, wait time.Duration, fn func(context.Context, Proof) error) (bool, error)
WithProof is With for feature/adaptor integration. The callback receives a live proof that its backend must check atomically with any protected write. It shares With's heartbeat, cancellation, callback isolation, limits and cleanup semantics.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns bounded acquisitions, guards and callbacks, borrowing its Backend. Construction is pure. Close cancels work and waits for actual cleanup; it never closes the borrowed adapter. Use Module to order cleanup before the adapter.
func NewManager ¶
NewManager validates configuration and constructs a manager borrowing backend without performing I/O.
func (*Manager) BorrowedBackend ¶
BorrowedBackend lets another framework feature use the SAME authority. It does not transfer adapter ownership; close dependent features before that adapter.
func (*Manager) Close ¶
Close starts cancellation once. A canceled caller stops waiting, while owned cleanup continues. Noncooperative domain callbacks delay Done; they are not abandoned. Do not call Close synchronously from one of this manager's own callbacks.
func (*Manager) Done ¶
func (m *Manager) Done() <-chan struct{}
Done closes when shutdown has drained all owned work and cleanup. A nil manager returns nil.
func (*Manager) Namespace ¶
Namespace identifies the authority scope shared by feature integrations.
func (*Manager) PollInterval ¶
PollInterval is the configured contention poll interval, shared by features that wait on this manager's leases (for example coordinated cache fills).
type Name ¶
type Name string
Name identifies a lease family; it is distinct from cache family names.
type Owner ¶
type Owner struct {
// contains filtered or unexported fields
}
Owner is an opaque, random adapter token. It is never exposed by application guards.
func ParseOwner ¶
ParseOwner copies and validates an owner token of exactly OwnerBytes bytes.
type Proof ¶
type Proof struct {
// contains filtered or unexported fields
}
Proof is an opaque adapter capability for one live lease owner. An adapter must validate it locally AND atomically compare Key/Owner at its authority when applying a protected mutation. Validate alone cannot fence a subsequent write. Proof cannot outlive its guard and must not be serialized into durable work.
func (Proof) Owner ¶
Owner is the opaque token for adapter wire encoding; it is not a fencing sequence.
type Semaphore ¶
type Semaphore[K any] struct { // contains filtered or unexported fields }
Semaphore retains its declaration's concrete resource key type.
func (Semaphore[K]) Acquire ¶
func (s Semaphore[K]) Acquire(ctx context.Context, key K, ttl, wait time.Duration) (*Guard, bool, error)
Acquire takes any free slot, waiting up to wait while all slots are held. The first attempt tries every slot once in random order (a zero wait stops there); each later poll tries at most 8 random slots. Like Leases.Acquire, the guard does not renew automatically; contention returns (nil, false, nil) and backend errors stop immediately without being treated as contention.
type SemaphoreDeclaration ¶
type SemaphoreDeclaration[K any] struct { // contains filtered or unexported fields }
SemaphoreDeclaration is a typed distributed concurrency limit: at most Slots holders of the same resource key at once across every process sharing the lease authority. Each holder owns one ordinary lease, so expiry, renewal, loss and cleanup follow the lease contract. Reuse one declared value.
func DefineSemaphore ¶
DefineSemaphore declares a family limiting each resource key to slots holders.
func (SemaphoreDeclaration[K]) Bind ¶
func (d SemaphoreDeclaration[K]) Bind(m *Manager) (Semaphore[K], error)
Bind shares the manager's declaration ownership, limits and lifecycle.
func (SemaphoreDeclaration[K]) Name ¶
func (d SemaphoreDeclaration[K]) Name() Name
Name returns the semaphore lease family name.
func (SemaphoreDeclaration[K]) Validate ¶
func (d SemaphoreDeclaration[K]) Validate() error
Validate checks the slot count and underlying lease declaration.
type Token ¶
type Token[K any] struct { // contains filtered or unexported fields }
Token is a transferable handle to one held lease of family K: its complete address, opaque owner and duration. It carries the owner secret, so treat it as a credential: formatting redacts it; only MarshalText exposes it. The type parameter keeps a token from being restored into another family's handle.
func (Token[K]) MarshalText ¶
MarshalText encodes the token, including its owner secret, for transfer.
func (*Token[K]) UnmarshalText ¶
UnmarshalText decodes and validates a token produced by MarshalText.
type TransferBackend ¶
type TransferBackend interface {
// LeaseTransfer atomically replaces from with to and renews ttl only while from owns key.
LeaseTransfer(ctx context.Context, key Key, from, to Owner, ttl time.Duration) (bool, error)
}
TransferBackend optionally hands a live lease to a new owner atomically: while from still owns key, the owner becomes to and the lease is renewed for ttl; otherwise nothing changes and it returns false. Restore requires it so every exported token is single-use. Memory and Redis implement it.