@workermill/agent 0.7.11 → 0.7.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/spawner.js +41 -2
- package/package.json +1 -1
package/dist/spawner.js
CHANGED
|
@@ -280,6 +280,7 @@ export async function spawnWorker(task, config, orgConfig, credentials) {
|
|
|
280
280
|
process: proc,
|
|
281
281
|
startedAt: new Date(),
|
|
282
282
|
status: "running",
|
|
283
|
+
resultEmitted: false,
|
|
283
284
|
};
|
|
284
285
|
activeContainers.set(task.id, container);
|
|
285
286
|
// Stream stdout/stderr to console (logs go to cloud via container's own HTTP calls)
|
|
@@ -287,6 +288,10 @@ export async function spawnWorker(task, config, orgConfig, credentials) {
|
|
|
287
288
|
const lines = data.toString().split("\n").filter((l) => l.trim());
|
|
288
289
|
for (const line of lines) {
|
|
289
290
|
console.log(`${ts()} ${taskLabel} ${chalk.dim(line)}`);
|
|
291
|
+
// Track if worker emitted ::result:: marker (means it called worker-complete itself)
|
|
292
|
+
if (line.includes("::result::")) {
|
|
293
|
+
container.resultEmitted = true;
|
|
294
|
+
}
|
|
290
295
|
}
|
|
291
296
|
});
|
|
292
297
|
proc.stderr?.on("data", (data) => {
|
|
@@ -302,8 +307,41 @@ export async function spawnWorker(task, config, orgConfig, credentials) {
|
|
|
302
307
|
const icon = code === 0 ? chalk.green("✓") : chalk.red("✗");
|
|
303
308
|
const status = code === 0 ? chalk.green("completed") : chalk.red(`failed (exit ${code})`);
|
|
304
309
|
console.log(`${ts()} ${taskLabel} ${icon} Container ${status} ${chalk.dim(`(${duration}s)`)}`);
|
|
305
|
-
//
|
|
306
|
-
|
|
310
|
+
// Safety net: if worker didn't emit ::result::, it may have died without calling worker-complete.
|
|
311
|
+
// Wait briefly for any in-flight API calls, then POST a fallback completion.
|
|
312
|
+
if (!container.resultEmitted) {
|
|
313
|
+
console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} No ::result:: marker seen — posting fallback completion in 15s`);
|
|
314
|
+
setTimeout(async () => {
|
|
315
|
+
try {
|
|
316
|
+
const fallbackResult = code === 0 ? "completed" : "failed";
|
|
317
|
+
const errorMsg = code !== 0 ? `Worker container exited with code ${code} without reporting completion` : undefined;
|
|
318
|
+
const resp = await fetch(`${config.apiUrl}/api/tasks/${task.id}/worker-complete`, {
|
|
319
|
+
method: "POST",
|
|
320
|
+
headers: {
|
|
321
|
+
"Content-Type": "application/json",
|
|
322
|
+
"x-api-key": config.apiKey,
|
|
323
|
+
},
|
|
324
|
+
body: JSON.stringify({
|
|
325
|
+
exitCode: code ?? 1,
|
|
326
|
+
result: fallbackResult,
|
|
327
|
+
errorMessage: errorMsg,
|
|
328
|
+
}),
|
|
329
|
+
});
|
|
330
|
+
const data = await resp.json();
|
|
331
|
+
if (data.status === "ignored") {
|
|
332
|
+
console.log(`${ts()} ${taskLabel} ${chalk.dim("Fallback completion ignored (task already transitioned)")}`);
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} Fallback completion applied: ${fallbackResult}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
catch (err) {
|
|
339
|
+
console.error(`${ts()} ${taskLabel} ${chalk.red("✗")} Fallback completion failed:`, err instanceof Error ? err.message : err);
|
|
340
|
+
}
|
|
341
|
+
}, 15_000);
|
|
342
|
+
}
|
|
343
|
+
// Clean up after delay (extended to allow fallback completion to finish)
|
|
344
|
+
setTimeout(() => activeContainers.delete(task.id), 90_000);
|
|
307
345
|
});
|
|
308
346
|
proc.on("error", (err) => {
|
|
309
347
|
container.status = "failed";
|
|
@@ -444,6 +482,7 @@ export async function spawnManagerWorker(task, config, credentials) {
|
|
|
444
482
|
process: proc,
|
|
445
483
|
startedAt: new Date(),
|
|
446
484
|
status: "running",
|
|
485
|
+
resultEmitted: false,
|
|
447
486
|
};
|
|
448
487
|
activeContainers.set(managerKey, container);
|
|
449
488
|
proc.stdout?.on("data", (data) => {
|