Skip to content

Fix tile cache purge timeout on large caches#216

Merged
stef-k merged 2 commits intomainfrom
feature/background-cache-purge
Mar 27, 2026
Merged

Fix tile cache purge timeout on large caches#216
stef-k merged 2 commits intomainfrom
feature/background-cache-purge

Conversation

@stef-k
Copy link
Copy Markdown
Owner

@stef-k stef-k commented Mar 27, 2026

Summary

Closes #207

  • Converts synchronous DeleteLruCache and DeleteAllMapTileCache admin actions to background Task.Run operations, returning HTTP 202 Accepted immediately
  • Adds atomic _purgeInProgress concurrency guard (Interlocked.CompareExchange) — second purge request returns 409 Conflict; tile-provider-change auto-purge skips gracefully
  • Broadcasts real-time progress via SSE (started/progress/completed/failed events) on admin-tile-cache-purge channel
  • Reduces _cacheLock file-delete chunk size from 100 to 10 with Task.Yield() between chunks to minimize CacheTileAsync writer starvation during large purges
  • Admin UI: animated Bootstrap progress bar, SSE reconnect on page reload mid-purge, automatic retry on SSE connection drop, disabled buttons during purge
  • Handles TOCTOU race between controller check and service guard — InvalidOperationException caught silently without broadcasting misleading "failed" event
  • Guard is always released in finally block, even on mid-purge failure or early return

Test plan

  • All 1412 existing tests pass
  • New PurgeAllCacheAsync_RejectsSecondConcurrentPurge — verifies only one purge runs, second throws
  • New PurgeLRUCacheAsync_RejectsSecondConcurrentPurge — same for LRU variant
  • New PurgeAllCacheAsync_BroadcastsProgressViaSse — verifies SSE events are broadcast with correct channel and payload structure
  • New PurgeLRUCacheAsync_BroadcastsProgressViaSse — same for LRU variant
  • New PurgeAllCacheAsync_GuardIsReleasedAfterFailure — verifies _purgeInProgress resets after completion
  • Manual: navigate Admin Settings, click "Clear LRU Cache" → progress bar appears, updates, stats refresh on completion
  • Manual: click purge button while another is running → "already in progress" warning
  • Manual: refresh page during purge → progress bar reconnects automatically
  • Manual: verify tile requests still work during purge (reduced lock contention)

Convert synchronous LRU/full cache purge to background operations
with real-time SSE progress reporting. Return HTTP 202 Accepted
immediately instead of blocking the request until completion.

- Add atomic _purgeInProgress guard (Interlocked.CompareExchange)
  to prevent concurrent purge operations; return 409 Conflict
- Broadcast progress via SSE (started/progress/completed/failed)
- Reduce file-delete lock chunk size 100→10 with Task.Yield()
  to minimize CacheTileAsync writer starvation during purge
- Admin UI: animated progress bar, on-load SSE reconnect,
  SSE retry on connection drop, disabled buttons during purge
- Tile-provider-change purge respects concurrency guard
@stef-k
Copy link
Copy Markdown
Owner Author

stef-k commented Mar 27, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

- Fix TOCTOU SSE gap: move "started" broadcast inside purge methods
  after CompareExchange guard, so losing concurrent requests never
  emit a dangling "started" event with no "completed"/"failed"
- Fix DRY: replace duplicated GetCacheStatus/GetCacheStatusFromScope
  with shared BuildCacheStatusAsync(TileCacheService) helper
- Fix SseService inconsistency: capture _sseService singleton before
  Task.Run instead of re-resolving from DI scope
- Fix flaky test: PurgeLRUCacheAsync_RejectsSecondConcurrentPurge
  now uses DelayingSseService to keep purge in-flight reliably
  (SlowTileHandler doesn't help since LRU purge doesn't fetch tiles)
- Fix inaccurate comment: _purgeInProgress doc now correctly states
  InvalidOperationException (not "409 Conflict" which is HTTP-layer)
@stef-k stef-k merged commit dcded4e into main Mar 27, 2026
1 check passed
@stef-k stef-k deleted the feature/background-cache-purge branch March 27, 2026 17:32
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.

LRU/full cache purge times out on large caches, shows error page despite successful deletion

1 participant