Documentation
¶
Overview ¶
Package halease is the HA fencing-lease primitive (ADR-0005 S1): a single cluster-wide lease with a strictly-monotonic epoch (the fencing token), arbitrated by a strongly-consistent backend. etcd is the default implementation (Etcd); Fake is the in-memory implementation the Culvert-side HA logic is unit-tested against.
S1 ships the primitive ONLY — nothing in the runtime consumes it yet. S2 wires Acquire into promotion, the keepalive loop, and self-fence; S3 stamps the epoch on every write sink; S5 adds flags/compose/GUI. Policy decisions (e.g. whether a clean shutdown releases the lease) deliberately live in those slices, not here.
Index ¶
- type Config
- type Etcd
- type Fake
- func (f *Fake) Acquire(_ context.Context, candidateID string) (bool, Status, error)
- func (f *Fake) Close() error
- func (f *Fake) ExpireForTest()
- func (f *Fake) Read(_ context.Context) (Status, error)
- func (f *Fake) Renew(_ context.Context, holderID string, epoch int64) (bool, time.Duration, error)
- func (f *Fake) SetNowForTest(now func() time.Time) (prev func() time.Time)
- type Provider
- type Status
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
Endpoints []string
TLS *tls.Config // nil = plaintext (operator's call; S5 wires flags)
TTL time.Duration // lease TTL; rounded up to whole seconds, min 1s; default 10s
DialTimeout time.Duration // default 5s
}
Config configures the etcd-backed Provider.
type Etcd ¶
type Etcd struct {
// contains filtered or unexported fields
}
Etcd is the etcd-backed Provider (ADR-0005 S1 default implementation).
func NewEtcd ¶
NewEtcd connects to etcd and returns the Provider. It does NOT touch the leader key — connection only.
func (*Etcd) Acquire ¶
Acquire implements Provider: a single transaction that puts the lease-bound key iff it does not exist. etcd deletes the key when the old holder's lease expires, so "free or expired" is exactly create_revision == 0.
func (*Etcd) Close ¶
Close implements Provider: closes the client connection WITHOUT revoking a held lease (release-on-shutdown is S2 policy; an unrevoked lease simply expires after its TTL).
func (*Etcd) Renew ¶
func (e *Etcd) Renew(ctx context.Context, holderID string, epoch int64) (bool, time.Duration, error)
Renew implements Provider: keepalive our lease, then re-verify the key still carries our (holder, epoch). The re-verify guards the fencing property even if a stray keepalive outlives the key.
type Fake ¶
type Fake struct {
// contains filtered or unexported fields
}
Fake is the in-memory Provider used to unit-test the Culvert-side HA logic (ADR-0005 S1). It implements the same contract the etcd backend does — the shared conformance suite in halease_test.go pins that both stay in agreement. Time is injectable so expiry is deterministic.
func (*Fake) ExpireForTest ¶
func (f *Fake) ExpireForTest()
ExpireForTest force-expires the current lease without changing the holder record — the next Acquire wins as if the TTL lapsed.
type Provider ¶
type Provider interface {
// Acquire attempts to take the lease for candidateID.
Acquire(ctx context.Context, candidateID string) (granted bool, st Status, err error)
// Renew keepalives the lease previously granted to (holderID, epoch).
Renew(ctx context.Context, holderID string, epoch int64) (ok bool, validFor time.Duration, err error)
// Read returns the current lease state.
Read(ctx context.Context) (Status, error)
// Close releases client resources. It MUST NOT revoke a held lease —
// release-on-shutdown is an S2 policy decision, not a primitive.
Close() error
}
Provider is the backend-agnostic fencing-lease interface (ADR-0005). Implementations MUST guarantee:
- Acquire grants iff the lease is free or expired, and every grant carries an epoch STRICTLY GREATER than any previously granted epoch (the fencing property). When denied, the returned Status describes the current holder.
- Renew succeeds iff (holderID, epoch) is still the live lease. A lost/expired/superseded lease returns ok=false with a nil error — loss is an outcome, not an error; errors are reserved for transport failures where the truth is UNKNOWN (callers must fail toward self-fence on both, but may retry transport errors within budget).
- Read never mutates state.
The backend — not the caller's wall clock — is the lease-time authority (ADR-0005 Finding 3).
type Status ¶
type Status struct {
Holder string // current holder's candidate ID ("" = free)
Epoch int64 // fencing token; strictly monotonic across the backend's life; 0 = never held
ValidFor time.Duration // remaining lease time as reported by the backend (0 = free/expired/unknown)
}
Status is a point-in-time view of the lease.