fix: forward abort signal to middleware and chunked requests#1697
Merged
blacha merged 1 commit intoMay 23, 2026
Merged
Conversation
blacha#1644 plumbed an optional `signal` through `SourceView.fetch` to the terminal source, but `SourceView.run` only seeds `req.signal` in the `middleware == null` branch — which never executes, because `fetch()` returns early when there is no middleware. So middleware never receives `req.signal`, even though `SourceRequest` declares it. A consumer that inspects `req.signal` (e.g. a concurrency limiter that drops a queued request when its caller aborts) therefore never sees the abort. `SourceChunk.fetchChunks` likewise dropped the signal on its per-chunk sub-requests. Seed `req.signal` from `options?.signal` in the middleware branch of `run()`, and forward the signal from `fetchChunks`, so middleware and chunked reads observe aborts. Adds tests for both. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
blacha
approved these changes
May 21, 2026
kylebarron
added a commit
to developmentseed/deck.gl-raster
that referenced
this pull request
May 22, 2026
Replace the internal LimiterMiddleware with an internal LimitedSource that wraps Source.fetch, composed beneath SourceChunk/SourceCache (cache hits still short-circuit before it). The middleware approach couldn't observe aborts: chunkd's SourceView doesn't forward the request signal to middleware, only to the underlying source via its terminal handler. Wrapping the source is the only layer that receives options.signal, so a request whose caller aborts while queued for a slot is now dropped before any network I/O — previously that never fired. Internal-only: GeoTIFF.fromUrl options, ConcurrencyLimiter, Priority, and PerOriginSemaphore are unchanged. Revert to a SourceMiddleware once chunkd forwards the signal (blacha/chunkd#1697); tracked in #565. Adds a LimitedSource test that aborts a queued read through the real acquire path (the gap that hid this). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kylebarron
added a commit
to developmentseed/deck.gl-raster
that referenced
this pull request
May 22, 2026
* docs: spec for coalescing tile fetches through deck.gl getTileData Design for #273: a TileBatcher in deck.gl-raster that coalesces deck.gl's per-tile getTileData calls into one getMultiTileData (-> geotiff.fetchTiles) call per zoom level, plus a chunkd request-scheduler middleware in geotiff so maxRequests bounds actual concurrent HTTP requests. No public fetchTiles API change; no loaders.gl dependency in geotiff. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(spec): per-origin concurrency limiter (gating only) Replaces the prior 2026-05-12 design (which scoped both gating and multi-tile coalescing into one spec). This narrows to gating: a ConcurrencyLimiter interface, PerOriginSemaphore default impl, Semaphore primitive (internal), and integration into GeoTIFF.fromUrl plus a module-level default on COGLayer.defaultProps so two layers on the same origin share one HTTP/1.1 connection pool out of the box. Multi-tile request coalescing (TileBatcher, getMultiTileData, fetchTilesSettled used from a layer) is explicitly deferred — the maxRequests / _pruneRequests interaction makes it more involved than expected and it's worth shipping gating first. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(geotiff): Semaphore primitive with signal-aware acquire A FIFO counting semaphore that hands out up to `maxRequests` concurrent slots. acquire(signal?) supports cancellation: an already-aborted signal rejects immediately without consuming a slot; aborting a queued acquire splices it from the queue and rejects, leaving the queue's FIFO order intact for surviving waiters. Internal primitive — not exported from the package. Building block for PerOriginSemaphore and limitFetch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(geotiff): ConcurrencyLimiter interface + PerOriginSemaphore A small public contract — acquire(url, signal?) returning a release fn — plus the default implementation that scopes slots per url.origin via an internal Map<origin, Semaphore>. Multiple consumers (e.g. two COGLayers on the same S3 bucket) targeting one origin share that origin's pool; consumers on different origins don't compete. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(geotiff): limitFetch helper Wraps a Source.fetch so each call goes through a ConcurrencyLimiter's acquire(url, signal?) — holding the slot for the underlying call's duration, releasing on resolve and on reject, and forwarding the caller's AbortSignal so a queued call dropped via abort never fires network I/O. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(geotiff): export ConcurrencyLimiter type and PerOriginSemaphore class Semaphore and limitFetch stay internal. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(geotiff): concurrencyLimiter option on GeoTIFF.fromUrl When supplied, wraps the data source's .fetch via limitFetch so every tile-data HTTP fetch holds a slot in the supplied ConcurrencyLimiter for its duration, forwarding the caller's signal so pan-away aborts drop queued requests. Header/metadata reads (through the cached SourceView) are not gated. Default is undefined (no gating) — the deck.gl-geotiff layers wire a shared PerOriginSemaphore default at their defaultProps level. Pass `null` to explicitly disable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(deck.gl-geotiff): default PerOriginSemaphore + fetchGeoTIFF option A module-level defaultConcurrencyLimiter = new PerOriginSemaphore({ maxRequests: 6 }) will be wired into COGLayer.defaultProps and MultiCOGLayer.defaultProps in the following commits, so layers on the same origin share one HTTP/1.1 connection pool by default. fetchGeoTIFF gains an options arg with concurrencyLimiter; forwarded to GeoTIFF.fromUrl for URL/string inputs. ArrayBuffer and pre-opened GeoTIFF inputs ignore it (the user already wired their own at open time, or there's no network to gate). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(deck.gl-geotiff): COGLayer.concurrencyLimiter prop + default Adds concurrencyLimiter to COGLayerProps with a default of the shared module-level PerOriginSemaphore({ maxRequests: 6 }). Two COGLayers on the same origin share one HTTP/1.1 connection pool out of the box; pass a custom ConcurrencyLimiter to override, pass null to disable. The prop is threaded into _parseGeoTIFF → fetchGeoTIFF → GeoTIFF.fromUrl. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(deck.gl-geotiff): MultiCOGLayer.concurrencyLimiter prop + default Same shape as COGLayer's prop: defaults to the shared module-level PerOriginSemaphore so a COGLayer and a MultiCOGLayer hitting the same origin share one HTTP/1.1 connection pool. Threaded through _parseAllSources → fetchGeoTIFF → GeoTIFF.fromUrl. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(geotiff): docstrings on Semaphore internals (PR #557 review) JSDoc on the Waiter fields and the _makeRelease / _releaseOne private helpers so each unit of the Semaphore primitive carries its own short explanation. No behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(geotiff): limitFetch → LimiterMiddleware class (PR #557 review) Replace the limitFetch fetch-wrapper with a LimiterMiddleware class that implements chunkd's SourceMiddleware, matching the shape of SourceChunk and SourceCache. Slot it into the existing SourceView middleware list in GeoTIFF.fromUrl, after SourceChunk + SourceCache, so cache hits skip the limiter and only uncached network reads consume slots. Header reads (through the cached header view) are now also gated — they're still mostly served from cache, but the rare cache miss now counts toward the per-origin cap, which is what callers actually want. No type cast (the @chunkd vs @cogeotiff Source-type impedance is avoided because everything composing the middleware in fromUrl is chunkd-typed from the start). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * cleaner * feat(geotiff): dynamic priority on ConcurrencyLimiter / Semaphore Adds an optional `getPriority` callback to `Semaphore.acquire`, `ConcurrencyLimiter.acquire`, and `LimiterMiddleware`. The callback returns a `number | readonly number[]` (lex-compared, missing trailing elements treated as 0); it's re-invoked by the limiter on every slot-open so dynamic state (e.g. distance from viewport center) re-sorts the queue without callers having to manage queue position themselves. Implementation uses an unsorted queue + linear-scan find-min on each release. A heap doesn't help here because dynamic priorities force us to re-evaluate every waiter's getPriority on every release anyway (we extract one minimum per release, not several). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(geotiff): thread getPriority through GeoTIFF.fromUrl + fetchGeoTIFF Adds optional getPriority callback to GeoTIFF.fromUrl and to the deck.gl-geotiff fetchGeoTIFF wrapper. fromUrl bakes it into the LimiterMiddleware so every header + tile-data fetch through this GeoTIFF's sources is dynamically prioritised against other waiters in the shared per-origin queue. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(deck.gl-geotiff): MosaicLayer passes distance-from-viewport-center as getPriority MosaicLayer now computes a dynamic `getPriority` closure per source, based on euclidean distance from the source's bbox center to the layer's current viewport center (degree-space — just used as an ordering key, great-circle isn't needed for sort order). It's threaded into the user-provided `getSource` callback's options so the consumer can forward it into `fetchGeoTIFF` / `GeoTIFF.fromUrl`. Each closure reads `this.context.viewport` fresh at call time, so the limiter re-evaluates priority on every slot-open — panning the viewport pulls newly-central sources to the front of the queue ahead of older edge sources, without callers having to manage queue position. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(examples/naip-mosaic): thread getPriority through getCachedGeoTIFF MosaicLayer now provides a dynamic `getPriority` closure (distance from viewport center to source bbox) in `getSource`'s opts. The example forwards it into `getCachedGeoTIFF` → `GeoTIFF.fromUrl({ getPriority })`, which bakes it into the LimiterMiddleware so every fetch through that COG's sources is dynamically prioritised against other waiters in the shared per-origin queue. Result: center-of-screen COGs jump ahead of edges in the limiter queue, and re-sort on pan. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(examples/naip-mosaic): actually install the limiter so priority can fire getCachedGeoTIFF was calling GeoTIFF.fromUrl with `getPriority` but no `concurrencyLimiter` — so fromUrl saw the limiter as undefined, skipped installing LimiterMiddleware entirely, and the priority closure was never consulted. Pass the shared defaultConcurrencyLimiter (now exported from @developmentseed/deck.gl-geotiff) so opens and tile-data fetches both go through the per-origin queue and dynamically re-sort by viewport-center distance. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(deck.gl-geotiff): MosaicLayer concurrencyLimiter prop Match COGLayer / MultiCOGLayer by accepting a `concurrencyLimiter` prop (default: shared `defaultConcurrencyLimiter`, opt out with `null`), and thread it into `getSource`'s opts alongside `getPriority`. Lets a consumer's `getSource` forward both straight to `GeoTIFF.fromUrl` (or spread `opts`), so priority can't silently no-op when the user forgets to also pass the limiter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(geotiff): gate header fetches through the concurrency limiter Header reads were temporarily un-gated during the priority work to isolate whether the data path alone was responsible for the bottom-left load order. Now that dynamic priority is in place and ordering works as expected, restore header gating so the browser's HTTP/1.1 6-per-origin cap isn't the only thing throttling header bursts — the limiter sees them, can interleave them with data fetches, and consumers keep explicit control over the queue. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(examples/naip-mosaic): forward MosaicLayer opts straight to GeoTIFF.fromUrl MosaicLayer now defaults `concurrencyLimiter` to the shared `defaultConcurrencyLimiter` and threads it into `getSource`'s opts alongside `getPriority`, so the example no longer has to import the default limiter or stitch the two together by hand. Collapse `getCachedGeoTIFF` to take an `opts` object that gets spread directly into `GeoTIFF.fromUrl`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(spec): cover dynamic priority + LimiterMiddleware + MosaicLayer Update 2026-05-19-concurrency-limiter-design.md to match what's actually shipped: chunkd `LimiterMiddleware` (not the original `limitFetch` function), both header and data paths gate (cache hits short-circuit before the limiter), dynamic `getPriority` re-evaluated per slot-open with linear-scan find-min, `Priority` type (`number | readonly number[]`, lex with trailing-zero fill), and MosaicLayer's viewport-distance closure threaded through `getSource`'s opts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(geotiff): export GeoTIFFFromUrlOptions; fix stale gating docstring Extract fromUrl's inline options object into an exported `GeoTIFFFromUrlOptions` interface so callers can name the type instead of reaching for `Parameters<typeof GeoTIFF.fromUrl>[1]` (PR #557 review). Also corrects the `concurrencyLimiter` doc, which still claimed header reads weren't gated — they are now, with cache hits short-circuiting before the limiter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(deck.gl-geotiff): address PR #557 review round 2 - Cancel in-flight header reads: COGLayer / MultiCOGLayer now hold an AbortController per parse, aborting the prior open when the geotiff/sources prop changes and on finalizeState, so stale reads release their limiter slot immediately. fetchGeoTIFF threads the signal through to GeoTIFF.fromUrl. - MosaicLayer only supplies getPriority for geographic viewports (WebMercatorViewport / _GlobeViewport), where the source bbox and viewport center share a lon/lat space; otherwise it's omitted and the limiter falls back to FIFO. - Drop MosaicLayer's redundant `=== undefined` defaulting — defaultProps already resolves concurrencyLimiter, so forward the prop straight through. - Rename the shared module-level default to DEFAULT_CONCURRENCY_LIMITER (UPPER_CASE constant). - Example forwards MosaicLayer's opts straight into GeoTIFF.fromUrl via the new GeoTIFFFromUrlOptions type; trim the verbose comment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(geotiff): thread signal into getTileSize header reads The tile-fetch path resolves each tile's offset/byte-count via image.getTileSize before reading the data. Those are header-source reads (lazy per-entry, served by the chunk cache, but a real network fetch on a cache miss) and now go through the concurrency limiter too. Without the signal, an aborted tile fetch left the getTileSize read running and holding its limiter slot. Forward the signal through getTile, getTiles, and the band-separate range lookup so the offset reads abort and release their slot alongside the data fetch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * options object * fix(deck.gl-geotiff): drop debounceTime from MosaicLayer A non-zero debounceTime stalls all source loading in MosaicLayer: deck.gl's RequestScheduler re-checks `isSelected` when the debounce timer fires and cancels anything not selected at that instant, and the flat, zoomless MosaicTileset2D model churns selection under viewport changes, so requests are perpetually cancelled and re-scheduled and nothing loads. Remove the prop from MosaicLayerProps and stop forwarding it to the inner TileLayer. COGLayer / MultiCOGLayer keep debounceTime support (hierarchical RasterTileLayer tiles, where it works). Tracked for a real fix in #562. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * shorter comment * refactor(deck.gl-geotiff): simplify COG layer AbortController to finalize-only Per PR #557 review: the per-parse abort-and-recreate handled the geotiff/sources prop changing mid-open, which is rare and was the "overkill" part. Drop it. Keep one controller for the layer's lifetime (created in initializeState, aborted in finalizeState) so a header read still in flight when the layer is removed is cancelled and its limiter slot freed — the one clearly useful case. MosaicLayer needs no controller of its own; it opens GeoTIFFs inside getSource during a tile load, where deck.gl already supplies a per-tile abort signal. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(deck.gl-geotiff): extract createGetPriorityCallback helper Per PR #557 review: the inline getPriority construction in MosaicLayer.getTileData was verbose. Pull it into a module-level createGetPriorityCallback(bbox, getViewport) helper that returns the distance-from-viewport-center callback (or undefined for non-geographic viewports). No behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(deck.gl-geotiff): extract openCogSources helper Per PR #557 review: the inline "open all COGs in parallel" block in MultiCOGLayer._parseAllSources was verbose. Pull it into a module-level openCogSources(entries, opts) helper that opens each source's GeoTIFF and resolves its projection, returning null when the signal aborts mid-open so the caller bails. No behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * remove comment * fix(geotiff): gate via source wrapper so abort-while-queued works Replace the internal LimiterMiddleware with an internal LimitedSource that wraps Source.fetch, composed beneath SourceChunk/SourceCache (cache hits still short-circuit before it). The middleware approach couldn't observe aborts: chunkd's SourceView doesn't forward the request signal to middleware, only to the underlying source via its terminal handler. Wrapping the source is the only layer that receives options.signal, so a request whose caller aborts while queued for a slot is now dropped before any network I/O — previously that never fired. Internal-only: GeoTIFF.fromUrl options, ConcurrencyLimiter, Priority, and PerOriginSemaphore are unchanged. Revert to a SourceMiddleware once chunkd forwards the signal (blacha/chunkd#1697); tracked in #565. Adds a LimitedSource test that aborts a queued read through the real acquire path (the gap that hid this). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(geotiff): abort a queued fromUrl header read end-to-end Proves the full chain (GeoTIFF.fromUrl -> open -> cogeotiff -> LimitedSource -> limiter) drops a header read still queued for a slot when its signal aborts, without ever fetching it. Saturate a maxRequests:1 PerOriginSemaphore with a first open, queue a second open behind it, abort the second, and assert it rejects and never hits the network. Closes the coverage gap that hid the chunkd signal bug. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(deck.gl-geotiff): don't forward undefined maxRequests from MosaicLayer MosaicLayer forwarded `maxRequests` to the inner TileLayer unconditionally, and its defaultProps never set it — so it passed `undefined`. deck.gl's createProps copies `undefined` over the prototype, shadowing TileLayer's default of 6 with `undefined`. That left Tileset2D with maxRequests undefined, which disables BOTH request throttling and `_pruneRequests` (gated on `maxRequests > 0`) — and `_pruneRequests` is the only thing that calls `tile.abort()`. So the concurrency limiter never received a cancellation: panned-out source header reads were never dropped, starving the current viewport. Only forward `maxRequests` when defined, so TileLayer's own default applies. Now pruning fires on pan, the tile signal aborts, and the limiter drops the queued header reads. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(deck.gl-geotiff): omit undefined when forwarding TileLayerProps Generalize the maxRequests fix: forward MosaicLayer's pass-through TileLayerProps (minZoom, maxZoom, extent, maxCacheByteSize, maxCacheSize, maxRequests) through a small omitUndefined() helper rather than tracking per-prop which can safely be undefined. deck.gl's createProps copies an explicit `undefined` over the prototype, so an unset prop forwarded as `undefined` shadows TileLayer's own default instead of falling back to it. Omitting undefined keys lets TileLayer's defaults apply uniformly, so we don't have to remember which props tolerate undefined. Behavior-neutral except the already-fixed maxRequests: the only other prop whose resolved value changes is minZoom (undefined -> TileLayer's 0), and that just bounds the tileset at viewport zoom >= 0 — the whole-world view and in — which is the normal range anyway. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * cleaner comment * concise * concsie * concise * concise * move up abort signal check * doc comment * fix(deck.gl-geotiff,geotiff): address round-2 review nits - comparePriorities: extract a normalizePriorityValue() helper that maps undefined/NaN to 0, so a getPriority returning NaN sorts as un-prioritized instead of silently comparing as a tie with everything (NaN < x and NaN > x are both false). - MultiCOGLayer._parseAllSources: bail when there are no sources, before the cogSources[0] (first source's projection) access that would throw on an empty `sources`. - naip-mosaic example: reword the maxCacheSize: 0 comment (it disables the cache, not "smaller"), and drop a leftover `window.data` debug assignment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * cleaner options * concise --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merged
blacha
pushed a commit
that referenced
this pull request
May 23, 2026
🤖 I have created a release *beep* *boop* --- <details><summary>fs: 11.5.2</summary> ## [11.5.2](fs-v11.5.1...fs-v11.5.2) (2026-05-23) ### Dependencies * The following workspace dependencies were updated * dependencies * @chunkd/source bumped from ^11.4.0 to ^11.4.1 * @chunkd/source-memory bumped from ^11.2.0 to ^11.2.1 * @chunkd/source-file bumped from ^11.2.0 to ^11.2.1 * @chunkd/source-http bumped from ^11.4.0 to ^11.4.1 </details> <details><summary>fs-aws: 11.6.2</summary> ## [11.6.2](fs-aws-v11.6.1...fs-aws-v11.6.2) (2026-05-23) ### Dependencies * The following workspace dependencies were updated * dependencies * @chunkd/fs bumped from 11.5.1 to 11.5.2 * @chunkd/source-aws bumped from 11.2.0 to 11.2.1 </details> <details><summary>middleware: 11.3.1</summary> ## [11.3.1](middleware-v11.3.0...middleware-v11.3.1) (2026-05-23) ### Bug Fixes * forward abort signal to middleware and chunked requests ([#1697](#1697)) ([372a96d](372a96d)) ### Dependencies * The following workspace dependencies were updated * dependencies * @chunkd/source bumped from ^11.4.0 to ^11.4.1 </details> <details><summary>source: 11.4.1</summary> ## [11.4.1](source-v11.4.0...source-v11.4.1) (2026-05-23) ### Bug Fixes * forward abort signal to middleware and chunked requests ([#1697](#1697)) ([372a96d](372a96d)) </details> <details><summary>source-aws: 11.2.1</summary> ## [11.2.1](source-aws-v11.2.0...source-aws-v11.2.1) (2026-05-23) ### Dependencies * The following workspace dependencies were updated * dependencies * @chunkd/source bumped from ^11.4.0 to ^11.4.1 </details> <details><summary>source-file: 11.2.1</summary> ## [11.2.1](source-file-v11.2.0...source-file-v11.2.1) (2026-05-23) ### Dependencies * The following workspace dependencies were updated * dependencies * @chunkd/source bumped from ^11.4.0 to ^11.4.1 </details> <details><summary>source-http: 11.4.1</summary> ## [11.4.1](source-http-v11.4.0...source-http-v11.4.1) (2026-05-23) ### Dependencies * The following workspace dependencies were updated * dependencies * @chunkd/source bumped from ^11.4.0 to ^11.4.1 </details> <details><summary>source-memory: 11.2.1</summary> ## [11.2.1](source-memory-v11.2.0...source-memory-v11.2.1) (2026-05-23) ### Dependencies * The following workspace dependencies were updated * dependencies * @chunkd/source bumped from ^11.4.0 to ^11.4.1 </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.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.
Fix two instances of
signalnot correctly being passed on through the middlewarecc @blacha