Skip to content

Fix iOS cancel-during-launch race with cancellable launch task wrappers#269

Merged
Kief5555 merged 1 commit intokief5555/iosfrom
capy/fix-ios-launch-cancel
Apr 12, 2026
Merged

Fix iOS cancel-during-launch race with cancellable launch task wrappers#269
Kief5555 merged 1 commit intokief5555/iosfrom
capy/fix-ios-launch-cancel

Conversation

@Kief5555
Copy link
Copy Markdown
Collaborator

@Kief5555 Kief5555 commented Apr 12, 2026

This PR fixes a race condition in OpenNOWiOS where tapping Cancel on StreamLoadingView during isLaunchingSession would leave the in-flight api.startSession() running because endSession() early-returned when activeSession == nil. The pending launch would then complete and start the session, ignoring the user's cancel request.

OpenNOWStore.swift:

  • Added launchTask private property to track the in-flight launch or resume operation.
  • deinit now cancels launchTask in addition to telemetryTask and sessionPollTask.
  • Added explicit CancellationError handling in launch() and resumeSession() to dismiss the loading overlay without setting an error when cancelled.
  • Added scheduleLaunch(game:) and scheduleResume(candidate:) synchronous wrappers that cancel any existing launchTask and start the new operation.
  • Updated endSession() to cancel and nil out launchTask immediately before checking activeSession, ensuring the pending API call is aborted even when activeSession is not yet set.

View Call Sites:

  • HomeView.swift: Replaced Task { await store.launch(game:) } with store.scheduleLaunch(game:) in both the featured section and the game grid.
  • BrowseView.swift: Replaced Task { await store.launch(game:) } with store.scheduleLaunch(game:).
  • LibraryView.swift: Replaced Task { await store.launch(game:) } with store.scheduleLaunch(game:).
  • SessionView.swift: Replaced Task { await store.resumeSession(candidate:) } with store.scheduleResume(candidate:).

Open in Capy OPEN-4 · 5.4

@Kief5555 Kief5555 added the capy Generated by capy.ai label Apr 12, 2026 — with Capy AI
Copy link
Copy Markdown
Contributor

@capy-ai capy-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added 1 comment

startSessionTasks()
lastError = nil
} catch is CancellationError {
showStreamLoading = false
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[🟡 Medium]

scheduleLaunch/scheduleResume can cancel an older task and immediately start a newer one, but the cancelled task’s catch is CancellationError still unconditionally sets showStreamLoading = false, which can hide the loading overlay while the newer launch/resume is still running. This produces incorrect UI state and can let users interact as if launch finished when it has not. Track task identity before mutating shared UI state (e.g., capture a local task token and only clear showStreamLoading if the completing/cancelled task is still launchTask) or move loading-state ownership to the scheduler. ```swift
// ios/OpenNOWiOS/OpenNOWiOS/OpenNOWStore.swift
} catch is CancellationError {
showStreamLoading = false
return
} catch {

@Kief5555 Kief5555 merged commit c430382 into kief5555/ios Apr 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

capy Generated by capy.ai

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant