test(managed-agent): size the FG8 letter fork budget to the measured lane wall clock (#14163)

Lane 38848525079 (hosted-harness-mysql, workflow_dispatch at R2 head
fee23d2d3c) reached the class's shared failsafe fork cleanly twice:
fg8a finished at ~683 s in, fg8b at ~704 s, then Surefire received the
shutdown {KILL} at exact ITS start plus 1800 s — the fork budget, not an
assertion, is what cut fg8d's choreography off. Fixes per wrap-up:

- packages/managed-agent-server/pom.xml: forkedProcessTimeoutInSeconds
  1800 → 3600 s, two sites; comment updated to describe the current
  five-letter / 21-case class (no longer the seven-case shape the
  original 1800 s headroom covered).
- scripts/tests/hosted-process-ci.test.js: hostedForkHealthySeconds
  1100 → 2400 with the lane-measured sourcing comment (five letters /
  twenty-one cases at run 38848525079, fork doubled for 2× headroom).
- .github/workflows/sdk-java.yml: hosted-harness-mysql job
  timeout-minutes 290 → 320, so the Verify step wraps its own fork
  (3600 s + wrap margin) instead of capping the suite under it.

Verified: pins all pass (hosted-process-ci.test.js 28/28), vitest
relation ceiling + healthySeconds ≤ fork holds (600 + 2400 = 3000 ≤
3600). No assertion-level changes; the budget answer stays in this PR
as review promised (P2 fork budget moves land in the same PR).
This commit is contained in:
Shaojin Wen 2026-10-16 15:00:50 +08:00
parent f36eda7f8a
commit a1ac638c08
3 changed files with 37 additions and 28 deletions

View file

@ -644,15 +644,13 @@ jobs:
hosted-harness-mysql:
name: 'Hosted process fault gates / MySQL 8.4 / Java 21'
runs-on: 'ubuntu-latest'
# The step ceilings (45 + 16×10 + 20 + 50 = 275 — the Verify, admission
# and O4 steps sit above their failsafe fork timeouts (the FG7 channel
# classes raised the hosted fork 900→1200 s and the L4 recovery class
# 1200→1800 s, with the FG8 monitor/run letters riding inside it; the
# admission gates share a 2400 s fork for both witness classes)) plus
# ~13 minutes for the uncapped setup steps (Checkout..Install MySQL
# binaries, the report checks) need ~288; 290 keeps a thin margin, and
# each arm buys its own 10 instead of sharing an envelope.
timeout-minutes: 290
# The step ceilings today (75 + 16×10 + 20 + 50 = 305 — the FG8 letters
# grew the shared failsafe fork to 3600 s, so Verify wraps it at its
# fork + 600 s plus margin, and admission plus O4 keep per-fork
# ceilings) plus ~13 minutes for the uncapped setup steps (Checkout..
# Install MySQL binaries, the report checks): 318 + 2 with the new fork
# story at 2× headroom, and each arm buys its own 10 like before.
timeout-minutes: 320
env:
QWEN_E2E_REGISTER_STORAGE: '1'
services:
@ -741,8 +739,9 @@ jobs:
# compile/surefire/spotbugs/checkstyle work: a step killed before its
# fork leaves no per-test failure lines, so the main-CI failure
# analyzer can only file an undiagnosable per-commit issue (#13503).
# hosted-process-ci.test.js pins this ordering.
timeout-minutes: 45
# hosted-process-ci.test.js pins this ordering; the fork budget is
# 3600 s, so the step wraps to fork + 600 s plus margin.
timeout-minutes: 75
env:
MAVEN_ARGS: '--settings ${{ runner.temp }}/setup-java-m2/settings.xml --toolchains ${{ runner.temp }}/setup-java-m2/toolchains.xml'
MYSQL_PORT: "${{ job.services.mysql.ports['3306'] }}"

View file

@ -335,12 +335,15 @@
covered, so a contended main runner killed
the fork before any test reported (#14125).
1800 s restores the 2× headroom. The FG8
monitor/run fault gates
(HostedMonitorRunFaultGatesIT: seven cases
with real background processes and >16 MiB
captures) add ~310 s measured on the lane,
inside the same 1800 s fork. -->
<forkedProcessTimeoutInSeconds>1800</forkedProcessTimeoutInSeconds>
monitor/run fault gates grew to five
letters / twenty-one cases with drain and
cancel choreography: on #14334's lane
(run 38848525079) the first three letters
finished by ~700 s into the fork, but the
1800 s budget still killed the fork JVM
before fg8d settled, so it doubles to
keep the same 2× headroom. -->
<forkedProcessTimeoutInSeconds>3600</forkedProcessTimeoutInSeconds>
</configuration>
<executions>
<execution>
@ -426,8 +429,11 @@
are independent fixtures sharing one fork: each
letter's @Timeout ceiling (600 s) plus the healthy
runtime must fit, the per-ceiling relation the CI
profile pins. -->
<forkedProcessTimeoutInSeconds>1800</forkedProcessTimeoutInSeconds>
profile pins. Fork measured on the lane (run
38848525079): four letters finished green by
~700 s, the budget still cut fg8d mid-choreography
at exactly 1800 s — 3600 s keeps the 2× headroom. -->
<forkedProcessTimeoutInSeconds>3600</forkedProcessTimeoutInSeconds>
</configuration>
<executions><execution><goals><goal>integration-test</goal><goal>verify</goal></goals></execution></executions>
</plugin></plugins></build>

View file

@ -372,12 +372,12 @@ describe('Hosted real-process gates', () => {
(total, step) => total + (step['timeout-minutes'] ?? 0),
0,
);
// Step ceilings today (45 + 16x10 + 20 + 50); the uncapped setup steps
// Step ceilings today (75 + 16x10 + 20 + 50); the uncapped setup steps
// need their own allowance — the job comment estimates it at ~13, so
// the enforced floor moves with that estimate, not the older 10.
expect(summed).toBe(275);
expect(summed).toBe(305);
expect(job['timeout-minutes']).toBeGreaterThanOrEqual(summed + 13);
expect(job['timeout-minutes']).toBe(290);
expect(job['timeout-minutes']).toBe(320);
});
it('runs every failover arm with its own runner arguments', () => {
@ -474,7 +474,7 @@ describe('Hosted real-process gates', () => {
// above tolerates anything up to step*60, so the value is pinned
// literally here — an unnoticed raise has no other red to land on.
if (profile === 'hosted-harness-mysql') {
expect(forkSeconds).toBe(1800);
expect(forkSeconds).toBe(3600);
}
},
);
@ -482,11 +482,15 @@ describe('Hosted real-process gates', () => {
// The Hosted*IT classes share one failsafe fork, so a case stalled to its
// @Timeout must still leave the fork its healthy runtime: on main the
// classes measured 437–546s with HostedTeamLeadMySqlIT adding ~65s, and
// the FG8 monitor/run letters add ~310s measured on the lane (~450s with
// CI headroom); with the fork itself ~14s, 1100s covers them. A larger
// ceiling lets failsafe kill the fork mid-run, and the classes left
// unrun never report, failing the gate undiagnosably (#13780).
const hostedForkHealthySeconds = 1100;
// the FG8 monitor/run letters grew from two letters / seven cases to five
// letters / twenty-one cases in #14334 — on that PR's lane (run
// 38848525079 at fee23d2d3c) four letters finished by ~700s into the
// fork, the fork was still killed at the old 1800s budget before the last
// letter reported, and the fork now sits at 3600s for the same 2×
// headroom. A larger ceiling lets failsafe kill the fork mid-run, and the
// classes left unrun never report, failing the gate undiagnosably
// (#13780).
const hostedForkHealthySeconds = 2400;
const hostedForkSeconds = () =>
Number(
read('packages/managed-agent-server/pom.xml')