Skip to content

fix: propagate AbortSignal on cancellation to stop iOS runner promptly#194

Merged
thymikee merged 4 commits intomainfrom
fix/ios-runner-cancellation-signal
Mar 9, 2026
Merged

fix: propagate AbortSignal on cancellation to stop iOS runner promptly#194
thymikee merged 4 commits intomainfrom
fix/ios-runner-cancellation-signal

Conversation

@thymikee
Copy link
Contributor

@thymikee thymikee commented Mar 9, 2026

Summary

  • Thread AbortSignal through the iOS runner request lifecycle so that client disconnection immediately interrupts in-flight HTTP fetches, retry delays, and retry loops
  • Register per-request AbortController in both socket and HTTP server paths; abort on client disconnect
  • HTTP server now detects client disconnection (req.on('close')) and cancels the associated request
  • retryWithPolicy and its internal sleep helper now respond to abort signals, breaking out of retry/delay cycles immediately
  • fetchWithTimeout in runner transport now combines timeout and request-cancellation signals

Closes #193

Test plan

  • TypeScript compiles cleanly (tsc --noEmit)
  • All 580 unit tests pass (npm run test:unit)
  • Manual: start an iOS runner session via the daemon, cancel the client mid-flight, verify the simulator stops promptly
  • Manual: verify HTTP RPC client disconnect triggers runner cleanup

🤖 Generated with Claude Code

… promptly

When a client disconnects (socket close or HTTP connection drop), in-flight
iOS runner operations now receive an AbortSignal that immediately interrupts
pending HTTP fetches, retry delays, and retry loops—ensuring detached
xcodebuild/runner processes are not driven after the parent workflow is canceled.

Closes #193

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link

github-actions bot commented Mar 9, 2026

PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://callstackincubator.github.io/agent-device/pr-preview/pr-194/

Built to branch gh-pages at 2026-03-09 15:33 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2eb4b1c093

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +306 to +309
req.on('close', () => {
if (!res.writableFinished) {
markRequestCanceled(requestIdForCleanup);
}

Choose a reason for hiding this comment

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

P1 Badge Detect HTTP disconnect from response/socket, not request close

req.on('close') is triggered after the request body finishes reading even for normal successful HTTP calls, so this handler runs on healthy /rpc requests before res is finished. With the current !res.writableFinished check, that marks requestId canceled during ordinary processing, which can spuriously abort in-flight iOS runner work even when the client is still connected. The disconnect hook should be tied to response/socket termination semantics instead of request completion.

Useful? React with 👍 / 👎.

shouldRetry: shouldRetryRunnerConnectError,
},
{ deadline, phase: 'ios_runner_connect' },
{ deadline, phase: 'ios_runner_connect', signal },

Choose a reason for hiding this comment

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

P1 Badge Propagate cancellation instead of falling back after abort

Passing signal into retryWithPolicy introduces a cancellation error path here, but this function still catches all retry errors and then continues to simulator fallback/connect-error wrapping. When a client disconnect aborts the signal, waitForRunner can still execute postCommandViaSimulator or surface Runner did not accept connection instead of exiting immediately as canceled, which defeats prompt cancellation and produces misleading failures.

Useful? React with 👍 / 👎.

@thymikee thymikee merged commit 4a22da9 into main Mar 9, 2026
7 checks passed
@thymikee thymikee deleted the fix/ios-runner-cancellation-signal branch March 9, 2026 15:37
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.

Detached iOS runner can continue driving simulator after parent workflow/client is canceled

1 participant