125Implement an offline-first data synchronization queue using IndexedDB
Problem
A field-sales app must keep working on a train with no signal: every change is applied locally at once and synced when the network returns, even if the tab was closed in between.
Implement createSyncQueue({ store, send, online = true, retryDelay = (attempt) => 1000 * 2 ** attempt }):
storeis a persistence adapter with asyncgetAll(),put(record)anddelete(id). In the browser it is backed by IndexedDB (see the adapter in the solution); in tests it is in memory.send(op)delivers one operation to the server. It rejects with aTypeErrorfor network problems (retryable), or with an error that has a 4xxstatusfor operations the server will never accept.
The queue returns { ready, enqueue(op, { coalesceKey }), flush(), setOnline(online), pending(), failed() }:
readyis a promise that resolves after previously stored records are loaded (they survive reloads).enqueuepersists{ id, op, attempts: 0, status: "pending", coalesceKey }before resolving, then starts a flush if online. IfcoalesceKeyis given and a pending record with the same key exists, replace itsopinstead of adding a new one (for example, ten edits to the same field send only the latest).flush()sends pending records in order, one at a time. On success, delete the record. On a network error, increaseattempts, stop flushing (keeping the order) and retry afterretryDelay(attempts - 1). On a 4xx error, mark the record"failed"(a dead letter for the UI to show) and continue with the next one. Only one flush runs at a time; callingflush()during a flush returns the same promise.setOnline(true)starts a flush;setOnline(false)stops starting new sends.pending()andfailed()return the records in order.
Try it yourself
Write your solution, run it, then submit to check it against the tests.
Press Run or ⌘ Enter to execute your code.
Step-by-step
enqueue writes the record to the store before anything is sent. If the tab closes one millisecond later, the operation is still on disk and will be sent on the next visit.
Unlock the full solution
What's inside
- Step-by-step
- Approach
- Solution
- Complexity
- Edge cases
- Follow-up questions
- Tests
Includes 3 code listings, 5 edge cases, 4 follow-up questions.
One-time payment by UPI, card or net banking. Launch price.