Skip to content

perf: throttle WMS playback requests to prevent overlapping GeoServer tile rendering - #229

Merged
mluena merged 2 commits into
developfrom
perf/OEMC-443-throttle-wms-playback-requests
Sep 7, 2026
Merged

perf: throttle WMS playback requests to prevent overlapping GeoServer tile rendering#229
mluena merged 2 commits into
developfrom
perf/OEMC-443-throttle-wms-playback-requests

Conversation

@mluena

@mluena mluena commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Overview

During timeline playback the map called updateParams({ DIM_DATE }) on every tick (2.5s), regardless of whether the previous batch of tiles had finished. OpenLayers does not cancel in-flight tile requests on updateParams(), so GeoServer kept rendering tiles the frontend then discarded — wasted server work whenever the server ran slower than the playback interval.

Two commits, and the second one is the important one.

perf: throttle WMS date changes against in-flight tiles implements the ticket as written: src/components/map/layers/buffered-tile-wms.tsx counts in-flight tiles via tileloadstart / tileloadend / tileloaderror, and a date arriving while tiles load is stored and applied once the source goes idle, coalescing several ticks into one request.

On its own that fixes the server load but makes playback stutter. The Timeline advances the date every 2.5s unconditionally, so the clock and the map decouple: the slider and date label keep moving while the map holds and then jumps, the coalesced dates never render, and the value tooltip (which reads date from state, not from the source) shows a date the map is not displaying.

perf: pace timeline playback on map tile readiness fixes that by making the clock wait for the map:

  • The WMS layers publish their in-flight tile state to mapTilesLoadingAtom (src/app/store.tsx), keyed per instance, derived into areMapTilesLoadingAtom.
  • Both timelines now step through usePacedTimelineStep (src/hooks/timeline.ts) instead of a bare useInterval. A step is held while tiles are loading and fires as soon as they settle; time already spent loading counts towards the interval, so the cadence is max(2.5s, tile load time).
  • Slider, date label, tooltip and rendered tiles stay on the same date, and no date is skipped.

The layer-level coalescing stays in place as a safeguard for date changes that do not come from playback (manual scrubbing, tick clicks). Its 10s guard (PENDING_DATE_TIMEOUT) also releases the loading flag, so a tile whose load event never arrives cannot stall the timeline.

Deviation from the ticket: OEMC-443 asks for the change to be isolated to buffered-tile-wms.tsx with the Timeline untouched. That constraint is what produced the stutter — coalescing at the layer while the clock keeps running cannot keep the slider and the map on the same date. Noted on the ticket.

Designs

N/A

Testing instructions

  1. Open /explore, activate a layer with a time dimension, open DevTools → Network, filter by GetMap.
  2. Play the timeline. Requests should come in non-overlapping batches — a new DIM_DATE batch only starts after the previous one settles, no interleaving.
  3. Throttle the network ("Slow 3G") and play again. Playback should slow down rather than skip: every date in the range still renders, the slider moves in step with the map, and no requests pile up.
  4. Back on a fast connection, confirm the cadence is still ~2.5s per step.
  5. Scrub the timeline manually and click individual ticks while tiles load — the map should end on the last date selected.
  6. No visual regression: old tiles stay visible until new ones load (no blink).
  7. Hover the map to open the value tooltip, then play — the tooltip value matches the date the map is showing.
  8. Compare mode: enable it, confirm the main timeline is still paused and the comparative timeline plays with the same pacing.

Not verified at runtime by the author.

Feature relevant tickets

OEMC-443


Checklist before submitting

  • Meaningful commits and code rebased on develop.
  • Update CHANGELOG
  • If this PR adds feature that should be tested for regressions when
    deploying to staging/production, please add brief testing instructions
    to the deploy checklist

OpenLayers does not cancel pending tile requests when updateParams() is
called, so a date change every playback tick left GeoServer rendering
tiles the frontend discards.

Track in-flight tiles via tileloadstart/tileloadend/tileloaderror on the
TileWMS source. Date changes that arrive while tiles are loading are
coalesced into the latest date and applied once the source goes idle,
which paces requests to the server's rendering capacity without touching
the Timeline components or the 2.5s interval.

A 10s guard applies the pending date anyway if a tile load event never
arrives, so a stuck request cannot stall playback for the layer.
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
oemc Ready Ready Preview Aug 5, 2026 8:54am

Request Review

Throttling date changes inside the WMS layer alone decoupled the map from
the playback clock: the slider and date label advanced every 2.5s while
the map held back and then jumped, skipping the coalesced dates.

Advance the timeline only once the map source is idle. The WMS layers
publish their in-flight tile state to a Jotai atom, and both timelines
step through usePacedTimelineStep, which waits for that state to clear
and counts load time towards the interval, so the cadence is
max(2.5s, tile load time) and no date is skipped.

The layer-level coalescing stays as a safeguard for date changes that do
not come from playback, along with its 10s guard, which now also releases
the loading flag so a missing tile event cannot stall the timeline.

This touches the Timeline components, which OEMC-443 ruled out, because
coalescing at the layer while the clock keeps running cannot keep the
slider and the map on the same date.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant