Skip to content
Support the creatorSupport

Offline queue, retries & backoff

Every recorded fix goes into a SQLite database on the device before anything is sent. Upload failures never lose a fix by themselves, and they never stop tracking.

  • One row per record, keyed by its uuid, oldest first.

  • Lives in app storage (on iOS, excluded from backups) and survives app kills, reboots and app updates.

  • Pruned after each insert:

    • beyond persistence.maxRecords (default 10,000), the oldest records are deleted;
    • records older than persistence.maxDays (default 7) are deleted.

    Both are logged with counts. At a 30 s moving interval, 10,000 records is roughly 80 hours of driving.

  • Uploads continue after stop() until the queue is empty.

const waiting = await LongPing.getQueueCount();
const sent = await LongPing.sync(); // upload now; resolves the number of records uploaded
await LongPing.clearQueue(); // delete everything waiting (e.g. on logout)

An upload is triggered when:

  • a record is inserted, and uploadIntervalSec is 0 or that many seconds have passed since the last attempt;
  • connectivity comes back;
  • you call sync() or setAuthorization();
  • the 60-second watchdog finds records waiting and the next-attempt time has passed.

Only one upload runs at a time. Each request carries up to maxBatchSize records (or one, with batch: false), and the run continues until the queue is empty or a request fails. sync() and setAuthorization() ignore both uploadIntervalSec and backoff.

During an upload the device holds a partial wake lock (Android, 60 s timeout) or a background task (iOS), so the OS doesn’t suspend it mid-request.

Response What happens to the records When the next try is
2xx Deleted. Normal pace; backoff resets.
401 / 403 Kept. After a token refresh (retried once), or after setAuthorization() / 15 minutes. See Authentication.
413 Kept. Immediately, with half the batch (min 1).
408, 429, 5xx, network error, timeout Kept. After backoff.
Other 4xx attempts + 1 each; deleted at 3 attempts (logged as dropped). The current run ends; records retry on the next trigger.
delay = min(900, 10 × 2^n) seconds, ±20 % jitter (n = failures in a row so far)

So roughly 10 s, 20 s, 40 s, 80 s … capped at 15 minutes. A Retry-After header in seconds wins over the computed delay (iOS also accepts the HTTP-date form). A 2xx resets the count.

When connectivity returns after a network failure, the device retries right away instead of waiting out the backoff. After a server error (5xx, 429) it waits.

  • onHttp fires for every attempt with { status, ok, count, responseText } (status 0 means a network error; responseText is the first 2 KB).
  • getState() includes queueCount and authorizationRequired.
  • The on-device log has a line for every request, backoff, pruning and dropped record.