Lease-Based Task Ownership for AI Agents: Stop Duplicate Work Before It Starts
Long-running agents need recoverable ownership, not permanent locks. Use leases, fencing tokens, heartbeats, and reconciliation to prevent duplicate work.
Two AI workers claiming the same job is not a cute race condition. It is how you send two invoices, publish two posts, or let separate agents rewrite the same file. Permanent locks avoid overlap until the owner crashes; then they turn your queue into a graveyard.
A lease gives one worker temporary ownership that can be recovered after failure. The trick is making expired owners harmless, because a slow agent may wake up after another worker has taken over.
What Should a Lease Record Contain?
Store a task ID, owner ID, expiry time, monotonically increasing fencing token, and the version of the task being processed. Claim the task with one atomic database operation: only an unowned or expired row may transition to your owner ID.
UPDATE tasks
SET owner_id = :worker,
lease_until = now() + interval '60 seconds',
fence = fence + 1
WHERE id = :id
AND (lease_until IS NULL OR lease_until < now())
RETURNING fence;
If the update returns nothing, another worker owns the task. Do not ask the model to negotiate. Back off, pick another job, or subscribe to a completion event.
Why Is Expiry Alone Not Enough?
Suppose worker A pauses during a slow model call. Its lease expires, worker B claims the job, and then A resumes. Both now believe they can write. A fencing token solves this by making every claim newer than the last.
Downstream mutation APIs must reject stale tokens. If worker A holds fence 41 and worker B holds 42, a database write, object-store update, or tool gateway should accept 42 and reject 41. Without enforcement at the side effect, the token is decorative.
Use heartbeats to renew healthy work, but cap the total runtime. An agent that loops forever should not retain authority forever. Separate a renewable execution lease from the immutable business command and its idempotency key.
How Do You Handle Long Model Calls?
Do not hold a database transaction open while waiting for an LLM. Claim the lease, commit, then call the model. Renew in a lightweight background loop and stop work immediately when renewal fails.
For tools with irreversible effects, verify lease ownership and fence immediately before execution. Record the effect in an idempotency ledger. Lease ownership prevents concurrent planners; idempotency prevents duplicate business effects across retries.
| Failure | Lease response | Extra control |
|---|---|---|
| Worker crash | Expire and reclaim | Idempotency key |
| Network partition | Reject stale fence | Reconciliation |
| Slow model response | Stop after failed renewal | Runtime budget |
| Duplicate queue delivery | One atomic claim wins | Unique task identity |
How Should You Test It?
Freeze a worker after claim, let the lease expire, and start a replacement. Resume the old worker and confirm every mutation rejects its fence. Kill workers before and after tool calls. Skew clocks in tests or, better, rely on database time so worker clocks do not decide ownership.
Track claim conflicts, renewal failures, expired active leases, stale-fence rejections, and reconciliation volume. If you never see rejections in chaos tests, the protection is probably not wired to the real side effect.
Leases make ownership recoverable. Fencing makes recovery safe. Idempotency makes effects repeatable. You need all three before autonomous workers can share a production queue without stepping on each other.
Sources
> Want more like this?
Get the best AI insights delivered weekly.
By subscribing, you agree to our Privacy Policy. You can unsubscribe at any time.
> Related Articles
AI Agent State Snapshots: Resume Long Jobs Without Repeating Side Effects
Durable agents need more than chat history. Snapshot plans, tool results, permissions, and idempotency state so a crash can resume safely instead of replaying the world.
Embedding Model Migration: Change Vectors Without Breaking Search
Embedding upgrades change the geometry of your index. Use versioned vectors, dual writes, shadow queries, and measured cutover instead of mixing incompatible representations.
LLM Request Coalescing: Stop Paying Twice for the Same Answer
When identical LLM requests arrive together, single-flight execution can collapse them into one upstream call—if cache keys, streaming, failures, and tenant boundaries are designed correctly.
Tags
> Stay in the loop
Weekly AI tools & insights.