Fix cold-cache tile loading: 503 + client-side retry for budget exhaustion#208
Merged
Fix cold-cache tile loading: 503 + client-side retry for budget exhaustion#208
Conversation
…ient-side retry After clearing the tile cache, map views showed persistent gray areas because budget-exhausted tile fetches returned 404 (permanent) instead of signaling a transient failure. Leaflet never retried, so tiles stayed gray until manual refresh. Changes: - Extract DbMetadataZoomThreshold constant (replaces magic number 9 in 9 locations) - Guard metadata insert with tileData != null to prevent ghost DB rows on budget exhaustion - Add RequestIdLoggingMiddleware + Serilog .Enrich.FromLogContext() for per-request log correlation - Introduce TileRetrievalResult to distinguish success/not-found/throttled states - Return HTTP 503 + Retry-After header when outbound budget is exhausted - Add RetryTileLayer (fetch-based L.TileLayer subclass) that retries on 503 with backoff - Centralize tile layer creation via createTileLayer() factory, replacing duplicated boilerplate across 13 JS files - Add inline tileerror retry fallback for 2 cshtml views with inline scripts Closes #206
936ffbf to
75190b8
Compare
- Add ±25% jitter to client-side retry backoff to prevent thundering herd
- Clamp Retry-After floor to baseDelay, reject zero/negative values
- Add explicit early return in CacheTileAsync for upstream HTTP failures
- Pass cancellationToken to ReadAsByteArrayAsync and Task.Delay
- Extract BudgetRetryAfterSeconds constant with doc linking to budget config
- Replace tileData?.Length with tileData.Length (guaranteed non-null after guards)
- Guard blob URL creation with signal.aborted check to prevent memory leak
- Add [Collection("OutboundBudget")] to prevent parallel test interference
- Add controller test for 503 + Retry-After on budget exhaustion
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.
Summary
RetryTileLayer(fetch-based Leaflet TileLayer subclass) that detects 503, readsRetry-After, and retries with exponential backoff -- tiles progressively stream increateTileLayer()factory, replacing duplicated boilerplate across 13 JS filesRequestIdLoggingMiddleware+ SerilogFromLogContextenrichment -- every log line now includesRequestIdfor cross-request correlationSize=0when tile fetch is aborted by budget exhaustionDbMetadataZoomThresholdconstant replacing magic number9(12 occurrences)Closes #206
Test plan
dotnet buildpasses (0 errors)dotnet testpasses (1404 tests)RequestIdin{Properties:j}SELECT * FROM "TileCacheMetadata" WHERE "Size" = 0returns zero rows after cold-cache loadcode-reviewersubagent