fix: poll for preview results to avoid undici headers timeout (#8682)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-04-02 20:55:46 +00:00
committed by GitHub
parent 55e8a5cff1
commit ff5fa9f64f
2 changed files with 58 additions and 29 deletions
+21 -26
View File
@@ -15,7 +15,7 @@ import { buildFolderPath, getMetadataFileName, loadNonDottedPathsSetting } from
import { requireLogin } from "../../core/auth.ts";
import { resolveWorkspace, validatePath } from "../../core/context.ts";
import { resolve, track_job } from "../script/script.ts";
import { resolve, track_job, pollForJobResult } from "../script/script.ts";
import { defaultFlowDefinition } from "../../../bootstrap/flow_bootstrap.ts";
import { SyncOptions, mergeConfigWithConfigFile } from "../../core/conf.ts";
import { FSFSElement, elementsToMap, ignoreF } from "../sync/sync.ts";
@@ -574,32 +574,27 @@ async function preview(
log.debug(`Flow value: ${JSON.stringify(localFlow.value, null, 2)}`);
// Run the flow preview
let result;
try {
result = await wmill.runFlowPreviewAndWaitResult({
workspace: workspace.workspaceId,
requestBody: {
value: localFlow.value,
path: flowPath.substring(0, flowPath.indexOf(".flow")).replaceAll(SEP, "/"),
args: input,
},
});
} catch (e: any) {
if (e.body) {
// If a failure_module ran, the body contains its result — not an error
if (e.body.result !== undefined) {
if (opts.silent) {
console.log(JSON.stringify(e.body.result));
} else {
log.info(colors.yellow.bold("Flow failed, error handler result:"));
log.info(JSON.stringify(e.body.result, null, 2));
}
process.exitCode = 1;
return;
}
// Run the flow preview — start the job, then poll for completion
const jobId = await wmill.runFlowPreview({
workspace: workspace.workspaceId,
requestBody: {
value: localFlow.value,
path: flowPath.substring(0, flowPath.indexOf(".flow")).replaceAll(SEP, "/"),
args: input,
},
});
const { result, success } = await pollForJobResult(workspace.workspaceId, jobId);
if (!success) {
if (opts.silent) {
console.log(JSON.stringify(result));
} else {
log.info(colors.yellow.bold("Flow failed, error handler result:"));
log.info(JSON.stringify(result, null, 2));
}
throw e;
process.exitCode = 1;
return;
}
if (opts.silent) {
+37 -3
View File
@@ -1118,6 +1118,27 @@ export async function track_job(workspace: string, id: string) {
}
}
const POLL_INTERVAL_MS = 2000;
export async function pollForJobResult(
workspace: string,
jobId: string,
): Promise<{ result: unknown; success: boolean }> {
while (true) {
const maybeResult = await wmill.getCompletedJobResultMaybe({
workspace,
id: jobId,
getStarted: false,
});
if (maybeResult.completed) {
return { result: maybeResult.result, success: maybeResult.success ?? false };
}
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
}
}
async function show(opts: GlobalOptions, path: string) {
const workspace = await resolveWorkspace(opts);
await requireLogin(opts);
@@ -1532,8 +1553,8 @@ async function preview(
}
}
} else {
// For regular scripts, use the standard preview API
const result = await wmill.runScriptPreviewAndWaitResult({
// For regular scripts, start the preview job then poll for completion
const jobId = await wmill.runScriptPreview({
workspace: workspace.workspaceId,
requestBody: {
content,
@@ -1544,8 +1565,21 @@ async function preview(
},
});
const { result, success } = await pollForJobResult(workspace.workspaceId, jobId);
if (!success) {
if (opts.silent) {
console.log(JSON.stringify(result));
} else {
log.info(colors.red.bold("Preview failed"));
log.info(JSON.stringify(result, null, 2));
}
process.exitCode = 1;
return;
}
if (opts.silent) {
console.log(JSON.stringify(result, null, 2));
console.log(JSON.stringify(result));
} else {
log.info(colors.bold.underline.green("Preview completed"));
log.info(JSON.stringify(result, null, 2));