fix: wait for qa gateway restart boundary

This commit is contained in:
Peter Steinberger
2026-04-27 07:13:35 +01:00
parent 1427c3a78d
commit 1dac448ff0
2 changed files with 58 additions and 0 deletions

View File

@@ -328,6 +328,32 @@ describe("buildQaRuntimeEnv", () => {
expect(__testing.isRetryableGatewayCallError("permission denied")).toBe(false);
});
it("waits for a fresh in-process restart boundary after the current log offset", async () => {
let logs = "old restart mode: in-process restart\n";
const offset = logs.length;
const wait = __testing.waitForQaGatewayRestartBoundary({
logs: () => logs,
offset,
pollMs: 1,
timeoutMs: 100,
});
logs += "signal SIGUSR1 received\nrestart mode: in-process restart\n";
await expect(wait).resolves.toBeUndefined();
});
it("times out when a SIGUSR1 restart never reaches the boundary", async () => {
await expect(
__testing.waitForQaGatewayRestartBoundary({
logs: () => "signal SIGUSR1 received\n",
offset: 0,
pollMs: 1,
timeoutMs: 1,
}),
).rejects.toThrow("qa gateway child did not reach restart boundary");
});
it("stages a live Anthropic setup-token profile for isolated QA workers", async () => {
const stateDir = await mkdtemp(path.join(os.tmpdir(), "qa-setup-token-state-"));
cleanups.push(async () => {

View File

@@ -268,6 +268,24 @@ async function fetchLocalGatewayHealth(params: {
}
}
async function waitForQaGatewayRestartBoundary(params: {
logs: () => string;
offset: number;
pollMs?: number;
timeoutMs?: number;
}) {
const timeoutMs = params.timeoutMs ?? 30_000;
const pollMs = params.pollMs ?? 100;
const startedAt = Date.now();
while (Date.now() - startedAt < timeoutMs) {
if (params.logs().slice(params.offset).includes("restart mode:")) {
return;
}
await sleep(pollMs);
}
throw new Error(`qa gateway child did not reach restart boundary within ${timeoutMs}ms`);
}
export const __testing = {
assertQaArtifactDirWithinRepo,
buildQaRuntimeEnv,
@@ -283,6 +301,7 @@ export const __testing = {
stageQaLiveAnthropicSetupToken,
stageQaMockAuthProfiles,
resolveQaLiveCliAuthEnv,
waitForQaGatewayRestartBoundary,
resolveQaOwnerPluginIdsForProviderIds,
resolveQaBundledPluginSourceDir,
resolveQaRuntimeHostVersion,
@@ -816,7 +835,20 @@ export async function startQaGatewayChild(params: {
if (!activeChild.pid) {
throw new Error("qa gateway child has no pid");
}
const restartLogOffset = logs().length;
process.kill(activeChild.pid, signal);
if (signal === "SIGUSR1") {
await waitForQaGatewayRestartBoundary({
logs,
offset: restartLogOffset,
});
await waitForGatewayReady({
baseUrl,
logs,
child: activeChild,
timeoutMs: 120_000,
});
}
},
async restartAfterStateMutation(
mutateState: (context: QaGatewayChildStateMutationContext) => Promise<void>,