@danhachuel/thunderbolt 0.5.74 → 0.5.76
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/package.json +1 -1
- package/scripts/cli.mjs +53 -8
package/package.json
CHANGED
package/scripts/cli.mjs
CHANGED
|
@@ -79,7 +79,9 @@ function hasScheduledAutomation() {
|
|
|
79
79
|
|
|
80
80
|
function hasPendingPipelineWork() {
|
|
81
81
|
const tasks = readStateJson("tasks.json", []);
|
|
82
|
-
|
|
82
|
+
// A UI Start coloca a tarefa em `doing`; `to_do` também é consumido pelo
|
|
83
|
+
// pipeline worker. Estes estados não dependem de automação de canal activa.
|
|
84
|
+
return Array.isArray(tasks) && tasks.some((task) => ["to_do", "doing"].includes(String(task?.state || task?.status || "").toLowerCase()));
|
|
83
85
|
}
|
|
84
86
|
|
|
85
87
|
function ensureRuntimeStorage() {
|
|
@@ -276,15 +278,17 @@ proxy.on("error", (error) => {
|
|
|
276
278
|
proxy.listen(publicPort, "127.0.0.1", () => {
|
|
277
279
|
console.log(`Thunderbolt: interface disponível em http://localhost:${publicPort}/`);
|
|
278
280
|
});
|
|
279
|
-
//
|
|
280
|
-
//
|
|
281
|
-
//
|
|
281
|
+
// Os workers são geridos pelo launcher para que um clique em Start na UI
|
|
282
|
+
// também active o processamento, mesmo sem automação de canal configurada.
|
|
283
|
+
// Cada worker só existe enquanto a respectiva fila tiver trabalho pendente.
|
|
282
284
|
let worker = null;
|
|
283
|
-
|
|
285
|
+
let pipelineWorker = null;
|
|
284
286
|
const restartExitCode = 75;
|
|
285
287
|
let shuttingDown = false;
|
|
286
288
|
let child;
|
|
287
289
|
let workerRestartTimer = null;
|
|
290
|
+
let pipelineRestartTimer = null;
|
|
291
|
+
let workerMonitorTimer = null;
|
|
288
292
|
|
|
289
293
|
function startAutomationWorker() {
|
|
290
294
|
if (shuttingDown || worker || !hasScheduledAutomation()) return;
|
|
@@ -308,6 +312,44 @@ function startAutomationWorker() {
|
|
|
308
312
|
});
|
|
309
313
|
}
|
|
310
314
|
|
|
315
|
+
function stopPipelineWorker() {
|
|
316
|
+
if (pipelineRestartTimer) {
|
|
317
|
+
clearTimeout(pipelineRestartTimer);
|
|
318
|
+
pipelineRestartTimer = null;
|
|
319
|
+
}
|
|
320
|
+
if (pipelineWorker && !pipelineWorker.killed) pipelineWorker.kill();
|
|
321
|
+
pipelineWorker = null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function startPipelineWorker() {
|
|
325
|
+
if (shuttingDown || pipelineWorker || !hasPendingPipelineWork()) return;
|
|
326
|
+
pipelineWorker = spawn(python, ["-m", "hermes_ui.pipeline_worker"], {
|
|
327
|
+
cwd: root,
|
|
328
|
+
stdio: "inherit",
|
|
329
|
+
env: runtimeEnv,
|
|
330
|
+
windowsHide: false,
|
|
331
|
+
});
|
|
332
|
+
pipelineWorker.on("error", (error) => console.error(`Thunderbolt pipeline worker: ${error.message}`));
|
|
333
|
+
pipelineWorker.on("exit", (code, signal) => {
|
|
334
|
+
pipelineWorker = null;
|
|
335
|
+
if (shuttingDown) return;
|
|
336
|
+
console.error(`Thunderbolt pipeline worker: terminou (código ${code ?? "-"}, sinal ${signal ?? "-"}).`);
|
|
337
|
+
if (hasPendingPipelineWork()) {
|
|
338
|
+
pipelineRestartTimer = setTimeout(() => {
|
|
339
|
+
pipelineRestartTimer = null;
|
|
340
|
+
startPipelineWorker();
|
|
341
|
+
}, 5000);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function monitorWorkers() {
|
|
347
|
+
if (shuttingDown) return;
|
|
348
|
+
if (hasPendingPipelineWork()) startPipelineWorker();
|
|
349
|
+
else if (pipelineWorker) stopPipelineWorker();
|
|
350
|
+
startAutomationWorker();
|
|
351
|
+
}
|
|
352
|
+
|
|
311
353
|
function startStreamlit() {
|
|
312
354
|
child = spawn(python, [streamlitBootstrap, "run", main, "--server.port", String(backendPort), "--server.address", "127.0.0.1"], {
|
|
313
355
|
cwd: root,
|
|
@@ -347,10 +389,13 @@ const stopWorker = () => {
|
|
|
347
389
|
shuttingDown = true;
|
|
348
390
|
proxy.close();
|
|
349
391
|
if (workerRestartTimer) clearTimeout(workerRestartTimer);
|
|
392
|
+
if (workerMonitorTimer) clearInterval(workerMonitorTimer);
|
|
350
393
|
if (worker && !worker.killed) worker.kill();
|
|
351
|
-
|
|
394
|
+
stopPipelineWorker();
|
|
352
395
|
};
|
|
353
396
|
process.on("SIGINT", stopWorker);
|
|
354
397
|
process.on("SIGTERM", stopWorker);
|
|
355
|
-
|
|
356
|
-
|
|
398
|
+
monitorWorkers();
|
|
399
|
+
// O launcher verifica apenas os JSONs locais; não existe timer no Streamlit
|
|
400
|
+
// nem worker persistente quando não há tarefa pendente.
|
|
401
|
+
workerMonitorTimer = setInterval(monitorWorkers, 2000);
|