Back to articles

2 min read

Where Untimer keeps its timer

A countdown kept in the browser drifts as soon as a tab sleeps. Untimer stores each session as one absolute moment on the server instead.

The first version of any timer counts down in the browser. It works on your machine, in your tab, while you are watching it. Then it meets the real world.

A tab in the background gets throttled. A phone locks and the page is frozen. Somebody refreshes. Somebody opens the same app on a laptop and a phone and sees two different numbers. Each of these is reported as a separate bug, and each gets its own patch, and none of the patches are the fix.

The fix was deciding who owns the truth

Untimer stores the session as one absolute moment: it started at this instant and it runs for this long. That goes in the database. Every client that wants to know how much time is left computes it from the current time, and every client gets the same answer.

The browser stopped owning time and started rendering it. A refresh recomputes. A frozen tab that wakes up recomputes. A second device recomputes. The bugs stopped being possible rather than being fixed one at a time.

What this made cheap

Once the server owned the session, several features that had been awkward became almost free.

  • Continuity across devices. Start on a laptop, finish on a phone. There is nothing to synchronise because there was never a second copy.
  • An honest record. The session already exists as a row with a start and a length. History is a query rather than a separate logging system to keep in step.
  • Trustworthy clients. A native application does not need to reimplement the timer, only to read it. Adding a platform means implementing a contract that already exists.

Two costs to handle

Two things.

The first is a network dependency. The client needs one round trip to learn what is running. Untimer shows a loading state that means loading and a failure state that means failure, rather than defaulting to zero and pretending nothing is running.

The second is clock skew. A client with a wrong system clock computes a wrong remaining time. The server sends its current time along with the session, so the client measures the offset once and applies it rather than trusting the device.

Where else this applies

The same shape fits anything that needs to show the same answer in two places at once: a countdown, a booking hold, a rate limit, a lock, a queue position.

One place holds the session, and everywhere else renders it. In Untimer that single decision replaced most of the synchronisation code we would otherwise have written.

Have something you want built?

Write a few lines about what you need and roughly when, and we will tell you whether we can help.