Repository navigation
fix(deck.gl-geotiff)!: stop passing renderSource an abort signal - #821
Merged
Merged
Conversation
MosaicLayer passed `renderSource` the signal of the item's open, and its
docs example and naip-mosaic passed it on to each COGLayer's `signal`.
That signal can't stop the layer's tile loads: deck.gl doesn't abort a
tile once it has loaded, and `renderSource` only draws items whose open
has finished. But it can arrive already aborted.
If an item's open is aborted while more than `maxRequests` opens are in
flight, and its `getSource` finishes anyway, as naip-mosaic's shared
per-URL cache allows, deck.gl keeps the source together with that
aborted signal. When the item is drawn again, every tile load of its
COGLayer aborts at once, and the item stays blank.
`renderSource` now gets only `{ source }`. A COGLayer already aborts its
loads that leave the view (#809), and the rest when MosaicLayer evicts
its item and the layer is finalized (#728).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kylebarron
commented
Oct 30, 2026
| getSource: async (item, opts) => | ||
| getCachedGeoTIFF(item.assets.image.href, opts), | ||
| renderSource: (item, { source, signal }) => { | ||
| renderSource: (item, { source }) => { |
Member
Author
There was a problem hiding this comment.
I see, so we only supply signal in getSource? Because renderSource shouldn't be loading headers (that's getSource's job), and then the tile reads happen inside the downstream layer (i.e. COGLayer)?
Member
Author
There was a problem hiding this comment.
Note
This reply was written by Claude (Claude Code), not by @kylebarron.
Yes, exactly.
getSourceis the only async work MosaicLayer does for an item: opening its source, which reads the headers. So it's the only place a signal can cancel anything. deck.gl aborts it when it cancels the item's load: when the layer is removed, or when the item leaves view while more thanmaxRequestsopens are in flight.renderSourceis synchronous. It only builds layers from the opened source and loads nothing itself.- The tile reads happen inside the layer it returns. COGLayer's inner TileLayer gives each tile load its own signal. That signal aborts when the tile leaves the view (feat(deck.gl-geotiff): coalesce COG tile reads by default #809) or the layer is removed (fix(deck.gl-raster): destroy tile textures when a raster layer is removed #728). COGLayer's own
signalprop stays, for an app that wants to cancel all of a layer's tile loads itself.
🤖 Written by Claude Code
kylebarron
added a commit
that referenced
this pull request
Oct 30, 2026
> [!NOTE] > This PR was written by Claude (Claude Code), not by @kylebarron. Bumps `version` to `0.10.0-beta.1` in the root `package.json` and in every `packages/*/package.json`, ready for the first 0.10 beta. The publish workflow sees `beta` in the version and publishes to npm under the `beta` dist-tag, so `latest` stays on 0.9.0. `CHANGELOG.md` gets a `v0.10.0-beta.1` section listing the 19 PRs merged since v0.9.0. ## Publish `@developmentseed/range-reader` by hand before tagging `@developmentseed/range-reader` (#806) isn't on npm yet, and `@developmentseed/geotiff` and `@developmentseed/deck.gl-geotiff` depend on it. The publish workflow can't create it: it publishes only through trusted publishing (OIDC), and npm can add a trusted publisher only to a package that [already exists](https://docs.npmjs.com/cli/v11/commands/npm-trust). Pushing the tag first would fail at `range-reader`. `pnpm publish --recursive` stops at the first failure, so packages published before it in the run would be out, and the rest, including `geotiff` and `deck.gl-geotiff`, would not. Once this is merged, from an up-to-date `main`: 1. Publish it once, as a public package under the `beta` tag. Its `prepublishOnly` script builds it first. ```sh cd packages/range-reader pnpm publish --tag beta --access public --no-git-checks ``` 2. Give it the same trusted publisher as the other packages (workflow `release.yml`, environment `release`), in its settings on npmjs.com or with: ```sh npm trust github @developmentseed/range-reader --file release.yml --repo developmentseed/deck.gl-raster --env release --allow-publish ``` 3. Tag the merge commit `v0.10.0-beta.1` and push the tag. The workflow skips `range-reader`, since that version is already on npm, and publishes the other ten packages. ## Breaking changes - #799: `COGLayer` takes a single `source`: an opened `COGSource`, or any input of `COGSource.open`. `geotiff` becomes `source`, `onGeoTIFFLoad` becomes `onSourceLoad`, and `epsgResolver` and `concurrencyLimiter` move to `COGSource.open`. - #801: `MultiCOGLayer` does the same with `MultiCOGSource`. `sources: { red: { url } }` becomes `source: { red: url }`, `MultiCOGSourceConfig` is removed, and files that don't share a CRS and an extent are rejected. - #804: `MosaicLayer`'s `sources` becomes deck.gl's `data`, and `MosaicSource` becomes `MosaicItem`. The callbacks get the item's opened source as `source`, and `onViewportLoad`'s entries are `{ item, source }`. - #821: `renderSource` gets only `{ source }`, without `signal`. - #812: `ZarrLayer` takes a `ZarrSource`, or a zarrita group or array, as `source`. `node`, `variable`, `metadata` and `epsgResolver` are removed (`metadata` becomes `ZarrSource.open`'s `geoZarrMetadata`), and the type parameters are now `ZarrLayer<DataT, Dtype, Store>`. - #807: `GeoTIFF.fromUrl` no longer takes `chunkSize` or `cacheSize`. They're `RangeReader` options now (`minMetadataReadBytes`, `cache.metadataBytes`). Two behavior changes aren't marked breaking: - #809: COG tile reads are coalesced by default, and `COGLayer` and `MultiCOGLayer` default to `maxRequests: 256` and `debounceTime: 50`. - #818: changing `updateTriggers.getTileData`, or ZarrLayer's `selection`, fetches tiles again, and the old tiles are removed at once. 🤖 Written by [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kylebarron
added a commit
that referenced
this pull request
Oct 30, 2026
… top of main Re-applies this PR's change to main's MosaicLayer, which stage 3 and #821 rewrote: the inner TileLayer is built from `getSubLayerProps()`, and each layer `renderSource` returns inherits the props it didn't set itself, such as `opacity`. `updateTriggers.all`, which `getSubLayerProps()` passes, no longer reaches the inner TileLayer, as in deck.gl's TerrainLayer: deck.gl's TileLayer would reload through `Tileset2D.reloadAll`, which leaks sources (#816). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
This PR was written by Claude (Claude Code), not by @kylebarron.
MosaicLayerpassedrenderSourcethe signal of the item's open. Both its docs example and the naip-mosaic example passed it on to each COGLayer'ssignal. That signal can't do what passing it suggests, and it can leave an item blank:renderSourceonly draws items whose open has finished.maxRequestsopens are in flight, and itsgetSourcefinishes anyway. Then deck.gl keeps the source, together with the aborted signal.renderSourcenow gets only{ source }. A COGLayer already aborts its loads that leave the view (#809). It aborts the rest when MosaicLayer evicts its item and the layer is finalized (#728).Migration
Drop
signalfromrenderSource's options. 0.10 already changes them from{ data }to{ source }.Tests
The bug, in deck.gl's
LayerManager. The test reproduces it step by step:maxRequests: 1, item A's open is aborted when A leaves the view while F's starts.getSourcefinishes anyway.Before the fix,
renderSourcegot an aborted signal. Now it gets{ source }.A type test:
renderSource's options are exactly{ source?: SourceT }. It fails ifsignalis added back.The workspace typecheck passes, naip-mosaic included.
In Chrome: naip-mosaic draws as before (924 NAIP items over Denver), with no new console messages.
🤖 Written by Claude Code