feat: keep the runner responsive under heavy capture load - #23
Open
Timo972 wants to merge 14 commits into
Open
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tatus caches Address two review findings on the HTTP layer split: - Pre-warm FBSDKVersion() and FBTestmanagerdVersion() on the main thread during startServing, before the HTTP server starts accepting connections. Both cache their result behind a dispatch_once, and /status is now served off the automation queue, so the first /status request could otherwise resolve the testmanagerd daemon proxy from a connection queue. - Unmark onControlQueue from the six session-required screencapture routes. Decorating a session-required route reads FBSession's static active-session state, which the automation queue writes without synchronization. Only the .withoutSession variants (already synchronization-safe) stay on the connection queue.
Whole-branch review found two Important cross-task defects in the runner-reliability-under-capture-load work: - FBSession's _activeSession static was read off-main by every control-route response builder (FBResponsePayload) while session create/kill wrote it on the main queue, an ARC data race with a use-after-free window. All reads and writes now go through @synchronized (FBSession.class) accessors, scoped tightly around the bare static access so XCUI/teardown work in kill/markSessionActive: never runs under the lock. - With per-connection queues, a second automation request could dispatch_sync onto the main queue while a first automation handler was spinning the run loop (FBRunLoopSpinner waiting on synthesis), and the nested run loop drain would execute the second handler reentrantly inside the first -- something the old shared connection queue serialized away. FBWebServer now funnels all non-control-route requests through a dedicated serial automation-funnel queue before hopping to main, restoring one-at-a-time semantics. Added FBWebServerDispatchTests. testAutomationRequestsDoNotNestInsideRunLoopSpin to pin the non-nesting behavior via a new /probe/spinning route. Also folds in two docs corrections: mobilerun-screencapture.md notes that only sessionless capture-control endpoints stay responsive during a blocked automation command, and the design spec notes the same for the broadcast status route plus the new automation funnel queue. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ge, and harden the pixel cap math
…et for min-clamped sizes Move the FBSDKVersion()/FBTestmanagerdVersion() warm-up in FBWebServer startServing to after keepAlive is set to YES and initialization is complete, so a /wda/shutdown that races the bounded legacy-daemon handshake (which can spin the main run loop up to 30s) clears keepAlive via stopServing instead of being negated by code that runs after it. Fix fb_sizeForWidth:height:pixelBudget: in FBVideoStreamSession so the minimum-size clamp (MAX(axis, 2)) can no longer push the product back over budget for skinny inputs (e.g. 10000x2 at budget 100 previously clamped to 1412px, 14x over budget). When the clamp pushes one axis to the 2px floor, the other axis is now shrunk to fit; honoring the budget outranks aspect ratio for extreme inputs. Budgets 1-3 can never be honored (2x2=4 is the minimum encodable size) and are now rejected by handleStartScreenCapture:'s maxPixels validation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…st server reference atomic
… notes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Three independent reliability improvements for the runner when screen capture is active:
EVENT_SYNTHESIS_TIMEOUT_MARGIN). If the system sheds the event under load, that one request fails with a 5xx instead of blocking the agent forever./status, the sessionless screencapture control endpoints, the unknown-route fallback) are served directly on the connection's queue. Automation routes keep their main-queue semantics and are additionally serialized through a funnel queue so at most one is in flight. A blocked automation command no longer takes down status probes or keyframe requests.POST /mobilerun/screencapture/startaccepts an optionalmaxPixelsargument (aspect-preserving downscale,0= uncapped). When omitted, devices with an A12 chip or older default to a 370k-pixel budget that is safe for sustained 60 fps encoding on that hardware class; newer devices are uncapped.Why
Sustained high-resolution capture on older hardware can make the system drop synthesized HID events. Previously a single lost acknowledgement wedged the agent permanently: the wait had no timeout, every route was funneled through the main queue, and all connections shared one socket queue — so even
/statusstopped answering and only a relaunch recovered the agent.Tests
UnitTestsbundle green locally (iOS sim); iOS and watchOS generic builds green locally; tvOS build and the integration suites run in CI.docs/request-dispatch.md; API docs updated indocs/mobilerun-actions.mdanddocs/mobilerun-screencapture.md.🤖 Generated with Claude Code