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

Offline Outbox, Idempotency, and Replay

Last updated: 4 Oct 20266 min read
tutorial
IntermediateBy AITrove Editorial

An offline outbox stores intended writes until a network path is available. It is not a second server. Each queued operation needs a stable ID, account scope, target resource, expected version, payload, creation time, and retry state. The server must enforce authorization and idempotency when the same operation is replayed after an uncertain response. Replaying in order matters when later operations depend on earlier ones; independent operations may run concurrently within a limit. A browser online event only indicates possible connectivity, so the client must attempt the request and inspect its actual result. Background synchronization is optional and not uniformly available; foreground replay is a required fallback.

Working case

Reviewer 29 edits case 47 on a train. The page stores a status change as operation op-47 with expected version 6 and labels it Queued, not Saved. Connectivity returns and the server commits the write, but the response is lost. Retrying op-47 with the same idempotency key returns the original committed result rather than making a second audit entry. Meanwhile another reviewer may have saved version 7; in that case the queued write becomes Conflicted and remains available for review. A permanent authorization error becomes Rejected, never an infinite retry loop.

Implementation boundary

javascript
function replayDisposition(status) {
  if (status === 412) return "conflicted";
  if (status === 401 || status === 403) return "rejected";
  return status >= 500 ? "retry-later" : "inspect-result";
}
console.log(replayDisposition(412));
// Output: conflicted

The helper sketches status handling; production code must also distinguish a lost response from an unaccepted request, parse the operation receipt, and cap retries. Persist the outbox in transactional browser storage suitable for the payload size, encrypt or avoid sensitive data according to the product threat model, and clear account-scoped operations on logout only under an explicit recovery policy. Use an idempotency key bound server-side to the actor and exact request fingerprint, with a retention window longer than the expected replay horizon. Retry transient failure with backoff and deadlines; stop on conflict or permanent rejection. Show the user each pending operation and provide a way to discard or resolve it.

Cost and boundaries

Queueing n operations requires O(n) local storage and replay work. A bound on operation count and bytes prevents a long offline period from consuming unlimited device space. Serial replay preserves dependencies but increases catch-up time; bounded parallelism helps independent cases yet complicates ordering and rate limits. Server idempotency records also consume storage for their retention window. Browser eviction can erase local data, so the UI must not promise guaranteed delivery before server acceptance. Measure pending age, replay success, duplicate suppression, conflicts, and local storage failure.

Failure trace

After a timeout, the client generates a new idempotency key for each retry. The first write actually committed, so later retries create duplicate audit records and notifications. Persist one key with the operation until terminal resolution. Another failure marks the queued change Saved when the online event fires, even though the server rejects its stale version. Separate Queued, Sending, Accepted, Conflicted, and Rejected states. A background sync handler may never run in one browser, so opening the app must also inspect and replay pending work with clear user feedback.

Verification

  • A lost response followed by replay creates one server mutation.
  • Conflict and permanent rejection remain visible terminal states.
  • Foreground replay works when background synchronization is unavailable.

Practice drill

Queue case 47 while offline and close the tab. Reopen under the same account, replay, and verify the operation ID is unchanged. Lose the first successful response, retry, and confirm one server audit record. Produce a 412 conflict and retain the local intent for review. Produce a 403 rejection and stop retries. Fill storage to its configured limit and show a usable error without claiming the new edit was saved. Repeat in a browser without background sync and verify foreground replay on return.

Decision note

Persist one stable operation identity and call an edit saved only after server acceptance.

Common Mistakes

  • Generating a new idempotency key for each retry.
  • Equating network availability with server acceptance.
  • Leaving an unbounded private outbox on a shared device.

Connected lessons

Cross-Tab and Offline Data Coordination; Cross-Tab Invalidation and Version Checks; Snapshot, Delta Cursor, and Gap Recovery; Collaborative Conflicts and Presence Expiry; Offline Sync and Conflict Policy; Idempotent Write Requests and Lost Responses; Conditional Writes and Lost-Update Prevention.

Apply and check

Build Project: multi-tab offline case review and review Web Development: operations and sync decisions quiz.

web-tech
web-development
Storage details