Skip to content

fix: concurrency correctness, background decode guarantee, and cache encapsulation#1

Draft
nonatomic-edd wants to merge 4 commits into
developfrom
fix/concurrency-plan
Draft

fix: concurrency correctness, background decode guarantee, and cache encapsulation#1
nonatomic-edd wants to merge 4 commits into
developfrom
fix/concurrency-plan

Conversation

@nonatomic-edd

Copy link
Copy Markdown
Collaborator

Fixes several concurrency bugs found via strict-concurrency analysis and the NonisolatedNonsendingByDefault language mode.

Fixed

  • downsample/fetchRemoteImage marked @Concurrent so image decoding always runs on the cooperative thread pool, regardless of language mode.
  • Coalescing race: cancellation and cleanup now verify task identity before touching activeTasks, preventing a stale handler from cancelling an unrelated request.
  • Cancelled requests now consistently throw CancellationError instead of leaking URLError(.cancelled).
  • StandardImageStreamerInstrumentation no longer runs a permanent 10Hz polling task; flushes are scheduled on demand.
  • SwiftUI environment defaults now share stable, pre-wired instances instead of constructing disconnected ones on each fallback access.

Breaking

  • ImageStreamer.init now accepts ImageCache instead of NSCache<ImageCacheKey, PlatformImage>, removing a process-wide retroactive @unchecked Sendable conformance.

…rumentation wakeups

  - Introduce ImageCache wrapper to replace the process-wide retroactive
    @unchecked Sendable on NSCache (breaking change to init signature)
  - Guard handleCancellation and active-task cleanup with task-identity
    checks to prevent stale cancellation handlers from clobbering newer
    requests for the same key
  - Normalize URLError(.cancelled) to CancellationError for callers
  - Replace the permanent 10Hz polling loop in StandardImageStreamerInstrumentation
    with on-demand scheduleFlush, eliminating idle wakeups
  - Fix SwiftUI environment defaults to reference stable shared instances
    instead of constructing disconnected ones on each fallback access
  - Convert coalescing tests to GatedMockFetcher for determinism
  - Add CLAUDE.md; remove GEMINI.md
…ode runs on the concurrent pool regardless of language-mode / NonisolatedNonsendingByDefault setting.
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