etcd-io/etcd
Lease
Source: server/lease/.
Purpose
Leases are TTL tokens. A client grants a lease, attaches one or more keys to it, and either renews it or lets it expire. When a lease is revoked or expires, all attached keys are atomically deleted. Leases are the foundation for client-side primitives like distributed locks (client/v3/concurrency/Mutex) and elections (concurrency/Election).
Directory layout
server/lease/
├── lessor.go # Lessor interface, lessor struct, Promote/Demote
├── lease.go # Lease object
├── lease_queue.go # min-heap by expiration
├── leasehttp/ # Server-to-server lease forwarding HTTP API
├── leasepb/ # protobuf for the bbolt encoding
└── metrics.goKey abstractions
| Symbol | File | Description |
|---|---|---|
Lessor interface |
server/lease/lessor.go |
The leader exposes Grant, Revoke, Renew, Lookup, Leases, Promote, Demote |
lessor struct |
same | Holds the in-memory lease map, the expiration heap, the checkpointer |
Lease |
server/lease/lease.go |
One lease: ID, TTL, remaining TTL, attached itemSet keys |
LeaseQueue |
server/lease/lease_queue.go |
Min-heap keyed by next-expiry time |
Checkpointer |
server/lease/lessor.go |
Function reference to EtcdServer.LeaseCheckpoint (proposed via Raft) |
RangeDeleter |
server/lease/lessor.go |
Function returning a TxnDelete; used to delete all attached keys atomically when a lease expires |
How it works
graph TD
grpc[v3rpc/lease.go] -->|Grant| server[EtcdServer]
server -->|Propose LeaseGrant| raft[Raft]
raft -->|toApply| apply[apply pipeline]
apply --> les[lessor.Grant]
les --> heap[LeaseQueue]
les --> bolt[(lease bucket)]
timer[expiration loop] --> heap
heap --> les2[lessor.expireExists]
les2 -->|propose LeaseRevoke| raft
raft --> apply2[apply LeaseRevoke]
apply2 --> rd[RangeDeleter]
rd --> mvcc[(mvcc.DeleteRange attached keys)]
apply2 --> les3[lessor.Revoke]
les3 --> boltKey behaviors:
- The lessor on the leader is the primary. Followers run a "demoted" lessor that does not expire leases; on leader change the new leader's lessor is
Promote()d. - TTL is rounded up to the resolution of the lease loop tick.
LeaseRenewis a non-Raft RPC on the leader: it just bumps the in-memory expiry. To survive failover, the lessor periodically checkpoints remaining TTL via a Raft proposal — seedefaultLeaseCheckpointInterval = 5 * time.Minute.- Followers handle
LeaseRenewby forwarding the request to the leader overlease/leasehttp/.
Configuration knobs
| Flag / constant | Default | Effect |
|---|---|---|
MaxLeaseTTL |
9_000_000_000 s | Server-side TTL cap |
defaultLeaseRevokeRate |
1000 leases/s | Throttle for expiration storms |
leaseCheckpointRate |
1000 entries/s | Throttle for batched checkpoints |
defaultLeaseCheckpointInterval |
5 min | How often remaining TTL is durably checkpointed |
defaultExpiredleaseRetryInterval |
3 s | Retry cadence for already-expired-but-not-yet-revoked leases |
Integration points
- Raft + apply: every lease lifecycle event (grant, revoke, attach, detach) is a Raft entry. Renewal is the only non-Raft path.
- MVCC:
RangeDeleteris supplied byEtcdServerso the lessor can delete attached keys without circular imports. - Backend (bbolt): leases are persisted in the
leasebucket (server/storage/schema/lease.go). - gRPC:
server/etcdserver/api/v3rpc/lease.gowraps the lessor for clients.
Entry points for modification
- New lease attribute →
server/lease/leasepb/lease.proto(regenerate), then plumb throughlessor.go. - New expiration policy →
LeaseQueueandlessor.runLoop(inlessor.go). - New API method (e.g. listing leases by attached key) →
lessor.go+server/etcdserver/api/v3rpc/lease.go.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.