A distributed lease can expire while its holder is unable to run. The holder may later resume with local state that still says it owns the lease, even though another client has already acquired a newer lease. If the protected storage or service accepts operations solely because the client once acquired the lease, two clients can mutate the same resource across different points in time.
A fencing token moves the decisive check from lease ownership into the protected resource. Each successful acquisition receives a token ordered after every earlier token. The resource records the greatest accepted token and rejects operations carrying an older value. The lease still coordinates acquisition, but the token constrains what a delayed former holder can do after it resumes.
Lease expiry does not revoke code already in flight
Consider client A acquiring a lease with a ten-second lifetime. It reads shared state, then stops executing long enough for the lease to expire. The pause might come from process suspension, runtime scheduling, host pressure, a long stop-the-world event, or loss of connectivity between the client and lease service.
Client B can acquire the lease after expiry and begin valid work. Nothing about B’s acquisition erases A’s memory, cancels an already queued storage request, or forces A’s process to terminate. When A runs again, its local control flow can continue from a point created during the old lease interval.
This is the stale-writer gap. A lease service can state that A no longer owns the lease, but that fact has no effect on a separate resource unless the resource has a mechanism that makes old authority unusable.
Extending lease duration changes the timing window rather than the authority model. Renewal also cannot establish safety if a client proceeds after a renewal result is delayed or ambiguous. A client-side clock check has the same limitation: the protected resource cannot infer current authority from a check performed earlier in another process.
Ordered tokens make authority visible at the resource boundary
A fencing scheme assigns a monotonically increasing token on successful lease acquisition. Suppose A receives token 41 and later B receives token 42. Every mutation sent to the protected resource carries the acquisition token.
The resource applies a simple ordering rule:
if request.token < highest_accepted_token:
reject request
else:
apply request
highest_accepted_token = request.tokenIf B’s operation with token 42 reaches the resource first, a later operation from A carrying token 41 is rejected. The resource does not need to ask the lease service whether A’s lease expired. It only needs durable or otherwise correctly synchronized state for the greatest token relevant to that resource.
The ordering must correspond to acquisition order. Random identifiers can distinguish lease instances, but equality alone cannot tell the resource which lease is newer. A UUID therefore provides identity but not fencing order unless another authoritative ordering mechanism accompanies it.
Token generation and resource enforcement form one safety contract
A counter at the lease service is useful only if successful acquisitions cannot receive values that move backward or collide in a way that breaks the required ordering. The exact mechanism can be a transactional sequence, a consensus-backed revision, or another source whose documented semantics provide the needed monotonic order.
The protected resource must also enforce the comparison atomically with the mutation it guards. A check followed by an unrelated write can recreate a race:
read highest token -> 41
accept token 42
concurrent request accepts token 43
write data for token 42If token validation and the protected mutation are not serialized under a suitable transaction, lock, conditional write, or equivalent primitive, an older operation can become visible after a newer one. Fencing is therefore not a property of the token format. It is a protocol spanning token issuance and the mutation boundary.
The persisted scope matters as well. A single global token watermark may serialize unrelated resources unnecessarily. A per-object watermark can provide finer isolation, provided every mutation for that object passes through the same ordering rule. The appropriate scope follows the ownership boundary the lease is intended to protect.
Fencing does not make arbitrary side effects reversible
Some targets cannot reject stale work. An email already handed to an external server, a physical actuator already triggered, or a legacy endpoint without conditional mutation semantics cannot retroactively apply a fencing comparison. In those cases, a fencing token at an upstream database may protect database state while leaving the external side effect outside that safety boundary.
A system can sometimes place an enforceable intermediary in front of the effect. For example, workers can write commands into a transactional outbox whose rows carry the current fencing token, while a single downstream component validates ordering before dispatch. That changes the architecture; it does not grant fencing semantics to an interface that lacks them.
The distinction also separates fencing from deduplication. An idempotency key answers whether repeated delivery represents the same logical request. A fencing token answers whether the caller’s authority is older than authority already observed by the resource. A stale writer can send a request only once and still require rejection.
Failover must preserve the ordering source
A fencing counter that resets after restart can admit stale authority. If an old client retains token 900, then a replacement lease service starts again at token 1, numerical comparison no longer represents acquisition order. The same problem appears if independent lease-service replicas issue overlapping sequences without coordination.
The ordering source therefore belongs to the failure model. Its persistence and failover semantics must ensure that a token issued after recovery remains ordered after tokens that may still exist in delayed clients or queues. Some systems use an existing consensus log index or storage revision for this purpose, avoiding a separate counter while retaining an authoritative order.
Integer width is another concrete boundary. A fixed-width counter must not wrap while older tokens can remain observable. Practical designs normally choose a range large enough that wraparound is outside the system lifetime, but the safety argument still depends on that assumption rather than on the word “monotonic” alone.
The resource, not the lease holder, closes the stale-writer gap
Lease ownership is temporal coordination. Fencing turns successive ownership epochs into values the protected resource can compare. That distinction becomes critical whenever a process can pause beyond lease expiry and later resume, because expiry changes the lease service’s state without erasing work already present elsewhere.
The resulting boundary is precise: token issuance must preserve acquisition order, every protected mutation must carry the token, and the resource must reject values older than the greatest authority it has accepted. Where any of those conditions is absent, a lease may still reduce concurrent work, but it cannot by itself exclude a delayed former holder from mutating the resource.