Lease
Exclusive, time-bound access to unique resources: one holder owns the world instance, the compute slot, or the license seat until the lease expires or is released. Resources carry a policy (durations, transferability, shared modes, fractional units), every grant carries a monotonic fencing token, contention can queue in a waiting room, and every lifecycle event lands in a durable history. Every example on this page was executed against a live server.
When to reach for it: one game server per match, license seats, a publish lock on a world instance, machine ownership during maintenance windows, transferable ownership between users and agents, and auditing who held what, when, and how it ended.
When not to: low-level coordination primitives - a mutex or compare-and-swap around a critical section - belong to Distributed State locks; a lease is a product-level grant with policy, queueing, and history. Queueing people into a capacity-limited experience at scale is the Waiting Room service - the lease waiting room queues callers for one resource.
Concepts
- Resources are registered up front (platform admin token required)
with a lease policy: default/max duration, renewal grace,
transferability, shared modes, fractional units, lifetime caps. The
resource_idis server-generated. - A lease is one holder's time-bound claim.
acquirereturns alease_id,expires_at, and a fencing token; the lease expires on its own unless renewed or released. - Fencing tokens are a per-resource monotonic counter, bumped on every acquire and transfer. Renew, release, and transfer all demand the current token, so a superseded holder cannot mutate the lease.
- Modes -
exclusive(the default) locks the whole resource;readandwriteleases can coexist with each other when the policy lists them inshared_modes. - Waiting room - acquiring with
on_conflict = join_waiting_roomqueues the caller instead of failing; see Contention: waiting room and bookings. - History durably records every acquire, renew, transfer, release, and reclamation with actor, fencing token, and status transition.
Register a resource
Registration is admin-only (a non-admin gets 403 insufficient_permissions); acquiring is not. There is no delete or
update endpoint for resources - register them deliberately.
snug lease resources create --kind world_instance --display-name "World A" \
--transferable --shared-mode read --max-duration-seconds 7200
snug lease resources get baubzZduHFaJUnXbcPSh # policy, active leases, bookings, wait countAcquire, renew, release
snug lease acquire baubzZduHFaJUnXbcPSh --duration 30m --metadata purpose=world-publish
snug lease status baubzZduHFaJUnXbcPSh
snug lease renew baubzZduHFaJUnXbcPSh --lease lse_PcyrehtbgqTE --fencing-token 1 --duration 30m
snug lease release baubzZduHFaJUnXbcPSh --lease lse_PcyrehtbgqTE --fencing-token 1Over HTTP, acquisition is a POST:
curl -X POST -H "Authorization: Bearer $SNUG_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"duration_seconds": 1800, "metadata": {"purpose": "world publish"}}' \
http://localhost:4000/api/v1/leases/baubzZduHFaJUnXbcPSh/acquire{
"status": 201,
"msg": "Created",
"data": {
"lease_id": "lse_JbhuLZhxLHyd",
"resource_id": "baubzZduHFaJUnXbcPSh",
"status": "active",
"mode": "exclusive",
"fencing_token": 8,
"expires_at": "2026-08-28T07:04:22.444553Z"
}
}While someone else holds the resource, acquire fails with
409 resource_unavailable. Retrying your own acquire with the same
--idempotency-key returns the original lease instead of erroring.
Behaviors to know, each reproduced live:
- Renew replaces the expiry with now + duration - it does not append to the current expiry. The total (time already elapsed + requested duration) is checked against the resource's max duration.
- A stale fencing token is rejected: renewing with the wrong token
fails
409 stale_fencing_tokenwithexpected N, got Min the message. - Only the holder (or an admin) may renew, release, or transfer -
anyone else gets
403 insufficient_permissions, even with a valid lease id and token.
Expiry, grace, and reclamation
An expired lease does not free the resource at expires_at. The holder
keeps exclusivity through the renewal grace window (60 seconds by
default), during which it can still renew; other callers keep getting
409 resource_unavailable. After the grace passes, the background
reclamation worker (every 30 seconds by default) sweeps the lease,
appends a reclaimed event to history, and admits the next waiter.
Verified live: a 5-second lease still showed active 11 seconds after
expiry, and history recorded reclaimed 71 seconds after. Plan for the
resource staying occupied up to grace + one worker interval past expiry;
release explicitly for an instant handoff.
Shared modes and fractional units
With shared_modes: ["read"], two holders' --mode read leases coexist,
each with its own lease id and fencing token; an exclusive acquire during
that time fails 409 resource_unavailable, and a mode not in the policy
fails 400 invalid_mode. A fractional policy
(fractional: {enabled: true, total_units: 4}, HTTP-only at
registration) makes shared-mode leases draw --units from a common pool:
after one holder takes 3 of 4 units, a 2-unit request fails
409 insufficient_units while a 1-unit request succeeds. Units do not
pool in exclusive mode - an exclusive lease always locks the whole
resource regardless of units.
Transfer
On a transferable resource, the holder hands the lease over without a
release/acquire gap:
snug lease transfer baubzZduHFaJUnXbcPSh --lease lse_eXeaApMyvWNM \
--fencing-token 2 --to-holder docs-waveExpiry is preserved; the fencing token rotates, so the old holder's token is dead the moment the transfer lands.
Validation and FSM guards
validate lets a downstream service check a presented lease id + fencing
token before doing work on the holder's behalf. It returns 200 with a
valid boolean and a reason - branch on valid, not the status code:
a stale token yields valid: false with
stale fencing token (expected 3, got 2). Resources may also declare
fsm_requirements (machine + transition pairs); validating with
--machine/--transition yields no matching fsm requirement unless
the resource declares that pair.
History
snug lease history baubzZduHFaJUnXbcPSh --page-size 20 --sort-order ascEvery entry carries the event (acquired, renewed, transferred,
released, reclaimed, ...), actor, fencing token at the time, status
transition, and metadata, with standard pagination; newest-first by
default.
Limits and configuration
Default lease duration 1 hour, max 24 hours, renewal grace 60 seconds,
reclamation every 30 seconds, up to 10000 waiters and 16 KB of lease
metadata by default - all tunable via the LEASE_* variables in the
Lease CONFIG reference.
Reference
- Lease API - every endpoint, callable
- Contention: waiting room and bookings - queueing on a held resource and reserving future windows
- Related: Distributed State for low-level locks, Waiting Room for large-scale user admission, FSM for the state machines that lease validation can guard