timescale.info
Sign inSign up

How OpenChronology was built

Every merged pull request of openchronology/timeline-app, its first week of commits and its releases; and before them the 2020 PureScript editor, from snapshots of its deleted repositories in the Wayback Machine. Written to this server through the HTTP API.

327 moments · 2020-03-09T00:15:08Z CE – 2026-11-02T20:11:21Z CE · by @athan · @athan

#84 · Keep a running cache of viewport windows and fetch ahead of the reader

  • timeline-app
  • pull request
  • packages

Closes #53: *for platform and desktop, treat browser as a running cache. Should populate cache with cache prediction, and have control over intelligently releasing portions of the cache.* ## Before Server timelines and desktop files kept **one** overscanned window (the view ± ¼ span) at one resolution. Any pan past a quarter span, any zoom across a resolution level, and any return to an earlier view sent a new query and showed a loading state. No request was made ahead of the reader. ## Running cache (`src/remote-cache.ts`) - **Several windows:** `ViewportCache` keeps up to 16 windows / 24 MiB at different places and resolutions. A view is answered by any fresh (≤ 30 s) window of its resolution that covers it. A newly stored window replaces the windows of its resolution that it contains. - **Prediction (`predict`):** once the view settles (400 ms), windows ahead of the reader are fetched one at a time: - a wide window at the view's resolution (two spans each side), for panning; - windows one level coarser and one finer, for zooming. They're ordered by the latest motion (pan, zoom in, zoom out), sized to stay within the server's limit of about 1,024 groups (width / 1,024 ≤ threshold), and skipped when already cached. - **Release:** over budget, windows farthest from the view are released first, scored by resolution distance (octaves), position (in view or window widths) and minutes since last use. The windows serving the view are never released. Windows unused for 5 minutes go, and a hidden page keeps only the windows covering its view (`release`). - **Fallback while fetching:** the window last drawn stays on screen if it overlaps the view, so visible markers and their grouping don't jump. Otherwise the covering window at the closest resolution stands in (`nearest`). ## App (`src/app.ts`) - **Priority:** the view's own query always goes first. A browser prefetch is aborted, and a desktop one (native requests can't be interrupted) is waited for, and then the view's query is retried. - **Marking:** prefetch queries carry `prefetch: true`. The server's query handler and the desktop store both ignore unknown fields (serde has no `deny_unknown_fields` on `Query`), so this needs no protocol change, and tests and logs can tell background requests apart. - **Capacity samples:** these still come only from the view's own queries. - **Comparison tracks:** they use the same class, so they keep several windows too, but they don't prefetch. ## Tests - `test/remote-cache.test.mjs` (5 new tests, 15 pass): - windows are retained across places and resolutions, and a wider window replaces the ones it contains; - predictions are ordered by motion, cover the view, stay within the server limit, and stop once fetched; - pans anywhere in a prefetched window are answered without a request; - over budget, the farthest windows go first while the serving and nearby ones stay; 5-minute expiry; - `release`, and the fallback choice. - `test/remote-cache-browser.mjs` (platform): - prefetches are recorded separately and held at first, so the existing hold-and-navigate steps stay deterministic; - returning to an earlier view now needs **no** request (previously it refetched); - after prefetches are released, panning both ways, zooming out and zooming in are all answered without a request. - `test/desktop-cache-browser.mjs`: prefetches are counted apart from the views' own requests; the desktop app prefetches too. - Local run in the `mcr.microsoft.com/playwright:v1.58.2-noble` image: remote cache, desktop cache, follow latest, comparison and drafts pass; the two cache checks passed 3 runs in a row. `npm test`: 207 pass. (In that container, `moment-dialog-browser.mjs` fails at line 115 on `main` too, so it's environmental; CI runs the full browser suite.)

Sources

Open #84 · Keep a running cache of viewport windows and fetch ahead of the reader in the timeline