DEV Community

Cover image for The signal dropped. Mid-trip. With your car.
Onkar Deokate
Onkar Deokate

Posted on

The signal dropped. Mid-trip. With your car.

The valet's location queue: saved first, sent second; offline waits, refused is dropped; ten tests.

You've handed your car keys to a stranger. That's what a valet is. They drive off to park it, and the only thing between you and mild panic is a dot on a map, moving.

Then the valet drives into a basement. Or under a flyover. Or into one of the many parts of Bangalore where 4G just... isn't.

The dot stops.

Yesterday I asked what happens next. Here's the answer, and it's the most careful forty lines in the whole app.

Why the obvious version loses data

The valet app reports a location fix every few seconds, from a background task. The obvious code is: on each fix, send it to the server.

That works right up until the send fails. The background task runs in a headless context where the connection may not even be up. A fire-and-forget send from there doesn't throw anywhere you can see. The fix is just gone, and the route on the driver's map has a hole in it exactly where they were most worried.

Saved first, sent second

So nothing is ever sent before it's stored. Every fix goes into a small on-phone queue, and then the queue tries to drain:

async enqueue(fix) {
  const queued = ordered([...(await read()), fix]).slice(-maxFixes);
  await write(queued);
Enter fullscreen mode Exit fullscreen mode

It still sends immediately. My first version enqueued and waited, which meant nothing reached the server between going online and going offline, and the valet's "last seen" went stale within a minute. The queue is for when a send fails, not a substitute for trying.

The queue has a ceiling, because a phone in a long tunnel shouldn't fill its storage with coordinates:

/** Roughly 15 minutes at the configured interval. */
export const MAX_QUEUED_FIXES = 200;
Enter fullscreen mode Exit fullscreen mode

Past that, the oldest fixes go and the newest always stay. Where the car is now matters more than where it was a quarter of an hour ago.

Offline waits. Refused is dropped.

Here's the subtle part. A send can fail for two very different reasons:

  • Offline. Worth trying again. Stop here, keep everything, in order.
  • Rejected. The server said no: say, a fix for a job this valet isn't assigned to. That will be a no forever. Retrying it would block every good fix queued behind it.
if (result.ok) continue;
// A refused fix is consumed; an unsendable one halts the drain so the
// rest keep their order for the next attempt.
if (result.reason === 'rejected') continue;
break;
}

await write(queued.slice(index));
Enter fullscreen mode Exit fullscreen mode

And when the signal comes back, the backlog replays oldest first, so the driver's map redraws the route in the order it was actually driven:

/** Oldest first, so a drain replays the route in the order it was travelled. */
function ordered(fixes: readonly LocationFix[]): LocationFix[] {
  return [...fixes].sort((a, b) => a.recordedAt - b.recordedAt);
Enter fullscreen mode Exit fullscreen mode

Two more things the queue survives: two drains racing each other (only one runs at a time, or the same backlog gets sent twice), and a corrupted stored value (the queue starts empty instead of crashing a background task nobody is watching).

Ten tests

Every one of those decisions has a test: send on capture, hold on failure, oldest first, the bound, refused-versus-offline, stop at the first unsendable fix, a corrupt store, a single malformed entry. Ten tests, all passing, and none of them need a phone.

What I'd tell myself before starting

"Offline" isn't an error to handle. It's a state the app spends real time in. Design for it first, and the happy path falls out for free.


Tomorrow: you've seen what happens in the tunnel. Tomorrow, the valet's side of the screen: taking a job, every step one tap, and the photo of the parked car that has to exist before the job can be confirmed. Follow the series.

ParkEase is a peer-to-peer parking marketplace for India, built solo and launching soon on Android.
Code: https://github.com/Deonkar/parkease ยท Music: ende.app (CC BY 4.0)

Top comments (0)