Skip to content

fix(watchos): terminate stalled WatchConnectivity requests safely - #331

Merged
turinglambdaai merged 8 commits into
mainfrom
fix/watchconnectivity-bounded-request-lifecycle
Oct 27, 2026
Merged

turinglambdaai merged 8 commits into
mainfrom
fix/watchconnectivity-bounded-request-lifecycle

Conversation

@turinglambdaai

@turinglambdaai turinglambdaai commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

What changes

WatchConnectivity sendMessageData did not bound the lifetime of an immediate request. A paired iPhone that never invoked its native success/error callback could leave the Swift caller suspended indefinitely, and callback/cancellation races risk resuming a checked continuation twice.

  • Introduce a portable, lock-serialized, exactly-once reply gate. It handles cancellation before or after continuation registration, native reply/error duplication and late callbacks without double resume.
  • Give outgoing immediate messages a configurable deadline (15 seconds by default, validated 1–120 seconds). Cancel the timer on terminal completion and return requestTimedOut for unresponsive peers.
  • Preserve strict 64 KiB request/reply validation, activated/reachable session checks and the iPhone-side explicit route allowlist.
  • Add macOS-runnable Swift concurrency tests for duplicate/late callbacks, cancellation before registration and finite timeout; document the semantics and that a timed-out command may still have been executed remotely.

Validation

Full CI is pending. Existing iOS/watchOS SDK and simulator compilation plus macOS Swift unit tests must pass before merge. Real paired-Watch connectivity and signed app packaging remain separate acceptance gates.

Additional iPhone-side hardening: the native reply handler also has a finite one-shot deadline. A stalled product route handler receives cancellation and the watch is sent a single empty failure reply. Pure Swift tests cover late duplicate replies and timeout fallback; current-head CI pending.

Final resource bound: also cap simultaneous immediate messages to four per direction (configurable 1–32), with overflow rejected before dispatch. An uncooperative router handler retains its reserved slot until it exits, preventing an unlimited backlog. Added a deterministic budget test. The latest head must pass a fresh CI run before merge.

Terminate WatchConnectivity requests after a configurable deadline, unblock
cancellation even if it races with continuation registration, and ignore
late or duplicate callbacks without resuming a checked continuation twice.
Keep policy and race tests portable to the macOS Swift test runner.
Give native reply handlers a one-shot finite deadline and cancel a stalled
product router when the iPhone cannot answer the paired Watch in time.
Tests cover timeout fallback and cancellation of a completed reply timer.
Bound simultaneous foreground requests to four per direction by default,
reject excess calls without dispatch, and keep slots reserved until handlers
actually exit even if a timed-out handler ignores cancellation.

Copy link
Copy Markdown
Owner Author

Maintainer follow-up (2026-10-27): Investigated the failing Swift protocol/runtime job. The only two test issues arose in phoneRelaySendsNativeReplyOnceEvenAfterTimeout, which assumed a 10 ms timeout must fire within a 40 ms wall-clock sleep under a highly concurrent test runner. Updated that test to wait for the actual one-shot native reply with a bounded 5 s poll, then assert late callbacks do not replace it (commit a55ab57). PR #332 has since been merged; resolved the resulting CHANGELOG merge conflict by preserving both change sets in merge commit 2713320. Compare against main now shows only the intended seven PR files. All six new-head CI workflows must pass before merging; earlier green runs do not qualify.

@turinglambdaai
turinglambdaai merged commit 9de6f5a into main Oct 27, 2026
23 checks passed
@github-actions
github-actions Bot deleted the fix/watchconnectivity-bounded-request-lifecycle branch October 28, 2026 06:24
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