refactor(apple): carry one phase Deadline through the runner interfaces and test cancellation as a matrix - #2473
Conversation
Size Report
Startup median (7 runs, lower is better):
|
|
No new code findings at fb52986. The refactor preserves the existing phase boundaries while passing deadline and cancellation together; the cancellation matrix checks outcomes, elapsed budget and probe counts. The inherited |
…es and test cancellation as a matrix
fb52986 to
37646f7
Compare
|
The reviewed patch is unchanged at 37646f7 and remains code-clean. CI now identifies one related fix: |
|
|
Suspected of breaking the iOS live lanes on main (Settings replay smoke and fixture E2E smoke: waits time out after the AX-bridge prepare is cancelled and the runner fallback retries without answering). Every CI run containing this change failed those lanes; runs without it in the same window passed. Reverting first (see the revert PR), then fixing forward with a live reproduction. |
|
Retracting the suspicion above: the local reproduction did not flip between this commit and its parent (4/4 green on both, identical request logs), the budgets in the red CI logs are byte-identical to green runs, and two of the four correlated failures were a Swift-only step on a different Xcode image. Revert #2474 is closed unmerged. The underlying flake (a 1 s readiness preflight abandoning a runner command that keeps the runner busy ~5 s) is filed separately. |
Follow-up to #2423, on the two points raised in review: encode one shared
Deadlineper runner phase in the owning interfaces, and turn #2423's ad-hoc cancellation cases into a matrix.Behavior is unchanged. This is an interface + test change.
1. One phase budget at the boundary
#2423 fixed the symptom (a cold toolchain-probe stall no longer adds its 30-45 s on top of the phase budget) but left the shape that produced it: each phase entry point took a number, converted it to a
Deadlineinternally, and then handed the deadline plus asignalonward in a separate bag - while the original number stayed in scope and reachable. Adoption took bothstartupTimeoutMsandphaseDeadline;requireRunnerPhaseRemainingMstook the deadline and a numeric fallback. A number that two callees can each turn into a budget is exactly the double-spend class.Now a phase is opened once, from the public numeric option, and every boundary below it takes that one object.
Before:
After:
ensureRunnerSessionstill takes the request-levelstartupTimeoutMsandbuildTimeoutMs, and is the one owner that converts - startup once, and the build as its own phase (the build must not be capped by what startup has left, as before). The cache prewarm inrunner-client.tsopens the build phase it starts.createRunnerPhaseDeadlineis gone: its two call sites became one factory that also carries the request signal, so the clock and the cancellation a phase is read against can no longer be paired up wrongly.ToolchainProbeClock.throwIfCanceled/attemptTimeoutMs), andstartRunnerSessionWithLeaseno longer re-resolves it.normalizeRunnerStartupTimeoutMsalready discarded non-finite values.2. Cancellation as a matrix
runner-cache-metadata.test.ts- one table-driven test overresolveExpectedRunnerCacheMetadata, each row naming when the request aborts, what the probe it lands on does, the expected outcome, the exact exec count and the wall clock spent:snapshot-source/cache-identity.test.ts- the same table over its smaller surface: aborted before the deadline is opened (0 execs), aborted while the first probe blocks and times out, aborted while it fails with a non-timeout error (the probe's own failure: a non-timeout failure is never retried, so there is no retry to cancel), aborted as the timeout unwinds before the retry, and no abort with the whole deadline spent (the timeout propagates unchanged).The named tests that cover non-cancellation behavior are kept as they were: budget sharing across the retry (
[30 s, 15 s]), a phase with 4 s left getting one 4 s attempt, and a probe whose own message merely says "timed out" not being retried.Removing the cancellation guard from
createToolchainProbeClockfails exactly the 7 abort rows and leaves the 2 non-abort rows green.Verification
typecheck(packages clean),lint,check:layering,check:affected --run,scripts/__tests__/eager-closure-budgets.test.ts(no growth), and the four touched test files.Note:
mainat 6d08de4 does not typecheck ---until(#2436) landed without theprojectConfig/recordedfields that #2453 made required onFlagDefinition, insrc/commands/cli-grammar/flag-definitions-action.ts. That failure is inherited, not from this branch, and clears on a rebase once main is fixed.