Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Outbox acknowledgements: require the current lease token

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

An outbox acknowledgement should update a row only when the caller still holds its current claim token.

Download Spring source kit

A stale owner must lose

Worker-A claims E-41. After the logical lease expires, worker-B reclaims it. An acknowledgement carrying worker-A's token updates zero rows; worker-B's token marks the row delivered. The fixture also checks that a delivered row cannot be claimed again. Counting affected rows makes a lost lease visible instead of treating every acknowledgement as success.

The token belongs in the update predicate with the event ID and incomplete state. A plain update by event ID lets a slow former worker mark another owner's attempt complete. The lease lesson shows how the owner changes. A unique token should be generated per claim attempt, not reused as a permanent worker name in production; this fixture's readable names are only deterministic test markers.

Fencing protects the row, not the destination

The old worker could already have sent an event before its stale acknowledgement failed. The token prevents a stale database state transition but cannot retract an external message. Keep the event ID stable across retries and make the destination mutation idempotent. Also record failed acknowledgement attempts so an operational view can distinguish a lease loss from a database outage.

Checked source

sql
update delivery_outbox
set delivered = true
where event_id = ? and claim_token = ? and delivered = false;

Verification boundary

OutboxLeaseContractTest.expiredLeaseCanBeReclaimedButOldWorkerCannotAcknowledge runs in the downloadable Spring source kit. The excerpt is shortened; the kit contains the complete tests.

Costs and limits

This H2 row-count test proves a conditional state transition in one database. It does not include token generation, concurrent worker scheduling, send acknowledgements, broker retries or dead-letter handling. Each acknowledgement is one indexed row update when event_id is a primary key.

Common Mistakes

  • Do not acknowledge by event ID alone after introducing leases.
  • Do not reuse a token across distinct claim attempts.
  • Do not call a fenced row update exactly-once message delivery.

Read next

Spring outbox claims: allow recovery after a worker lease expires, Spring consumer deduplication: commit the event ID with the mutation, Spring transactional outbox: commit a receipt and event row together.

spring
spring-boot
outbox-fenced-ack
Storage details