Skip to content

Backend & Distributed Systems

Resumable Client Timers and Durable Intent

Designing a browser timer that survives reloads, preserves one logical request identity, and avoids duplicate completion records.

Published 2 min read
#backend#react#local-storage#resilience

A timer is often treated as visual state, but a running session is user intent. Reloading the page should not reset elapsed time or generate a second completion record.

Persist an anchor, not every tick

Writing remaining seconds every second creates noise and can drift when a tab is suspended. The client stores a start timestamp, duration, learning reference, and request ID. On restoration it computes elapsed time from the current clock.

json
{
  "requestId": "session-generated-on-start",
  "unit": "study-unit",
  "startedAt": "2026-09-13T10:00:00.000Z",
  "durationSeconds": 1800
}

The interval updates the display, while the timestamp remains the source of truth. When the computed remaining time reaches zero, the same request ID is sent to the server.

Recovery and idempotency are one design

Local restoration alone is insufficient. The browser may send completion, receive no response, and reload. If restoration generates a new ID, the server cannot recognize the retry. Preserving the ID connects client recovery to the database uniqueness constraint.

The stored shape is versioned and validated before use. Invalid JSON, negative durations, or a unit that no longer exists are discarded safely instead of crashing the page. Successful completion clears local state only after the server acknowledges the session.

Test lifecycle interruptions

Browser validation covered start, reload, restored display, and completion. API tests covered identical retries and semantic conflicts. The remaining limitation is cross-device continuation: browser storage is intentionally local. Supporting multiple devices would require authenticated server-side leases and a clear policy for two active timers.

Related writing