Skip to main content

Leases

A lease grants a client time-bound ownership of a resource. As long as the client keeps the lease alive, it owns the resource. If the client stops or fails, the lease expires and ownership is released automatically. Leases are the foundation for locks, leader election, and distributed workers.

The problem leases solve

In a single process, ownership is implicit. If a function is running, it owns the work; if the process dies, the work stops with it.

In a distributed system that assumption breaks. Multiple instances may attempt the same work, a process may crash without warning, a machine may become unreachable, or a network partition may isolate a node.

Consider a worker that picks up a job, marks it "in progress", and then crashes. Without a recovery mechanism, the job stays "in progress" forever, and no other worker can tell whether it is safe to take over. A lease removes that ambiguity: ownership carries an expiry, so a failed owner's claim releases on its own.

What a lease means

A lease is not just an expiration timer on data. It represents a statement of ownership: this client owns this resource, but only for a limited time.

That time bound is the point.

  • While the client stays alive and renews, it keeps the lease.
  • If the client disappears, the lease expires.
  • When the lease expires, ownership is released and any keys attached to it are removed.

The system recovers without manual intervention.

Leases compared with TTL

Leases and time-to-live (TTL) both involve time, but they answer different questions. Confusing them leads to incorrect designs, so keep the distinction clear.

ConceptQuestion it answersOn expiry
TTLHow long should this data exist?The data is removed. No ownership is involved.
LeaseWho is responsible for this resource right now?Ownership is released and the resource becomes available for reassignment.

Use TTL to control how long a cache entry or session lives. Use a lease to control which worker owns a job, which instance holds a lock, or which node is the leader.

When to use a lease

Reach for a lease whenever a piece of work or a resource must have a single valid owner, and that ownership must not be allowed to go stale after a failure. The following patterns are the common cases.

Distributed workers

You want exactly one worker to process each job, and you want another worker to take over if the first one crashes. Worker A acquires a lease, marks the job active, and renews the lease while it works. If Worker A crashes, the lease expires and the job becomes available again. No manual cleanup runs.

Leader election

You need one instance to coordinate while the others follow. A node acquires a lease as leader and renews it periodically. If the leader fails, its lease expires and another node acquires the lease and takes over. This gives you automatic failover.

Resource ownership

Several instances contend for one shared resource, such as a file, an external API quota, or a scheduled task. A lease ensures only one instance owns the resource at a time, and ownership resets automatically if that instance fails.

Presence and heartbeat

You want to represent live presence, such as active workers or connected clients. Each instance writes a key attached to a lease and keeps the lease alive. If the instance disappears, the lease expires and its presence key is removed automatically.

Working with leases

The following steps show the full lifecycle: grant, attach, renew, and release.

Grant a lease

Call GrantAsync with a duration. It returns a result whose Value is the new lease id, which you own for that window.

var lease = await client.Leases.GrantAsync(TimeSpan.FromSeconds(10));
var leaseId = lease.Value;

Attach work to the lease

Attach a key to the lease with the Put.WithLease option when you write it. The key's lifetime is now tied to the lease: when the lease ends, the key is removed. Put lives in the Clustron.Zaris.Client namespace.

await client.PutAsync(
"worker:1",
"active",
Put.WithLease(leaseId));

Keep the lease alive

Call KeepAliveAsync before the lease expires to extend your ownership. As long as you keep renewing, you remain the owner.

await client.Leases.KeepAliveAsync(leaseId);
warning

Renew well before the lease duration elapses, not at the moment it ends. Renew on an interval shorter than the lease, for example every few seconds for a ten-second lease, so network delay or a scheduling pause does not let the lease lapse. If a renewal is late, the lease expires, your attached keys are removed, and another client can take ownership — all without an error being thrown on your side. Treat a missed renewal as a loss of ownership.

Stop renewing

If you stop calling KeepAliveAsync, the lease expires on schedule. Ownership is released and every key attached to the lease is removed. This is the automatic-recovery path that runs when a client fails.

Revoke explicitly

Call RevokeAsync to release ownership immediately instead of waiting for expiry. Use this when a worker finishes cleanly.

await client.Leases.RevokeAsync(leaseId);

Why leases are safer than raw locks

A traditional lock has a failure mode: if the owner crashes while holding it, the lock may never be released, and everything waiting on it blocks forever. A lease cannot get stuck this way, because every ownership carries an expiry. No claim becomes permanent by accident, which makes leases failure-safe by design. This is exactly why Zaris locks are built on leases.

Next steps

  • Locks to build exclusive access on top of leases.
  • Watch to react when leased keys appear or expire.