fix(qa-lab): improve health timeout error message and fix port-free check

This commit is contained in:
Peter Steinberger
2026-04-06 19:35:06 +01:00
parent 37b7e22e13
commit 27dc1bd0fc
2 changed files with 16 additions and 7 deletions

View File

@@ -35,6 +35,7 @@ describe("runQaDockerUp", () => {
expect(calls).toEqual([
"pnpm qa:lab:build @/repo/openclaw",
`docker compose -f ${outputDir}/docker-compose.qa.yml down --remove-orphans @/repo/openclaw`,
expect.stringContaining(
`docker compose -f ${outputDir}/docker-compose.qa.yml up --build -d @/repo/openclaw`,
),
@@ -77,6 +78,7 @@ describe("runQaDockerUp", () => {
);
expect(calls).toEqual([
`docker compose -f ${outputDir}/docker-compose.qa.yml down --remove-orphans @/repo/openclaw`,
`docker compose -f ${outputDir}/docker-compose.qa.yml up -d @/repo/openclaw`,
]);
} finally {

View File

@@ -36,7 +36,7 @@ async function isPortFree(port: number) {
return await new Promise<boolean>((resolve) => {
const server = createServer();
server.once("error", () => resolve(false));
server.listen(port, () => {
server.listen(port, "127.0.0.1", () => {
server.close(() => resolve(true));
});
});
@@ -112,6 +112,7 @@ async function execCommand(command: string, args: string[], cwd: string) {
async function waitForHealth(
url: string,
deps: {
label?: string;
fetchImpl: FetchLike;
sleepImpl: (ms: number) => Promise<unknown>;
timeoutMs?: number;
@@ -120,7 +121,8 @@ async function waitForHealth(
) {
const timeoutMs = deps.timeoutMs ?? 240_000;
const pollMs = deps.pollMs ?? 1_000;
const deadline = Date.now() + timeoutMs;
const startMs = Date.now();
const deadline = startMs + timeoutMs;
let lastError: unknown = null;
while (Date.now() < deadline) {
@@ -136,9 +138,14 @@ async function waitForHealth(
await deps.sleepImpl(pollMs);
}
throw new Error(
`Timed out waiting for ${url}${lastError ? `: ${describeError(lastError)}` : ""}`,
);
const elapsedSec = Math.round((Date.now() - startMs) / 1000);
const service = deps.label ?? url;
const lines = [
`${service} did not become healthy within ${elapsedSec}s (limit ${Math.round(timeoutMs / 1000)}s).`,
lastError ? `Last error: ${describeError(lastError)}` : "",
"Hint: check container logs with `docker compose -f <compose-file> logs` and verify the port is not already in use.",
];
throw new Error(lines.filter(Boolean).join("\n"));
}
export async function runQaDockerUp(
@@ -213,8 +220,8 @@ export async function runQaDockerUp(
const qaLabUrl = `http://127.0.0.1:${qaLabPort}`;
const gatewayUrl = `http://127.0.0.1:${gatewayPort}/`;
await waitForHealth(`${qaLabUrl}/healthz`, { fetchImpl, sleepImpl });
await waitForHealth(`${gatewayUrl}healthz`, { fetchImpl, sleepImpl });
await waitForHealth(`${qaLabUrl}/healthz`, { label: "QA Lab", fetchImpl, sleepImpl });
await waitForHealth(`${gatewayUrl}healthz`, { label: "Gateway", fetchImpl, sleepImpl });
return {
outputDir,