channel-worker 2.5.4 → 2.5.5
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/lib/command-poller.js +49 -1
- package/package.json +1 -1
package/lib/command-poller.js
CHANGED
|
@@ -1340,10 +1340,58 @@ class CommandPoller {
|
|
|
1340
1340
|
// Pause on the Renderers tab; profile should stay closed until Resume.
|
|
1341
1341
|
const isPaused = (r) => r && r.health_state === 'paused'
|
|
1342
1342
|
&& (!r.pause_until || new Date(r.pause_until).getTime() > Date.now());
|
|
1343
|
-
|
|
1343
|
+
let stillOffline = renderers.filter(r => !runningRenderers.includes(r) && !isPaused(r));
|
|
1344
1344
|
const pausedCount = renderers.filter(isPaused).length;
|
|
1345
1345
|
console.log(`[scene-dispatch] running=${runningRenderers.length} cap=${parallelLimit} (flowkit=${flowkitQ} dom=${domQ}) offline=${stillOffline.length} paused=${pausedCount} queue=${queueCount} names=[${runningRenderers.map(r=>r.name)}]`);
|
|
1346
1346
|
|
|
1347
|
+
// ROUND-ROBIN ROTATION — when a running renderer just finished its
|
|
1348
|
+
// scene (no in-flight cmd) AND there's at least one OFFLINE sibling
|
|
1349
|
+
// AND queue has more work, close the just-finished one so the next
|
|
1350
|
+
// cycle launches the sibling. Result: scenes alternate veo03 →
|
|
1351
|
+
// veo04 → veo03 → veo04 … instead of one renderer claiming
|
|
1352
|
+
// everything. Required for shared-Google-account safety: keeping a
|
|
1353
|
+
// browser idle on Flow page keeps refreshing tokens / pinging
|
|
1354
|
+
// telemetry → Veo flags "2 concurrent sessions per account" → captcha.
|
|
1355
|
+
// Closing it = 0 idle sessions, only 1 active at a time.
|
|
1356
|
+
if (queueCount > 0 && stillOffline.length > 0 && runningRenderers.length > 0) {
|
|
1357
|
+
const stoppedNames = [];
|
|
1358
|
+
for (const r of [...runningRenderers]) {
|
|
1359
|
+
// Skip externally-launched profiles (user opened manually via NST UI)
|
|
1360
|
+
// — we don't own their lifecycle.
|
|
1361
|
+
if (!this._profileLastActivity[r.nst_profile_id]) continue;
|
|
1362
|
+
try {
|
|
1363
|
+
const c = await this.api.rendererHasCommands(r.nst_profile_id);
|
|
1364
|
+
if (c > 0) continue; // busy → keep alive
|
|
1365
|
+
console.log(`[scene-dispatch] Round-robin: closing idle ${r.name} to rotate to sibling`);
|
|
1366
|
+
await this.nst.stopProfile(r.nst_profile_id);
|
|
1367
|
+
delete this._profileLastActivity[r.nst_profile_id];
|
|
1368
|
+
if (r.name) delete this._profileLastActivity[r.name.toLowerCase()];
|
|
1369
|
+
const idx = runningRenderers.indexOf(r);
|
|
1370
|
+
if (idx >= 0) runningRenderers.splice(idx, 1);
|
|
1371
|
+
stoppedNames.push(r.name);
|
|
1372
|
+
// The now-closed renderer becomes a fresh offline candidate for
|
|
1373
|
+
// future cycles (won't relaunch immediately — sibling goes first
|
|
1374
|
+
// because its last_command_assigned_at is older).
|
|
1375
|
+
stillOffline.push(r);
|
|
1376
|
+
} catch (e) {
|
|
1377
|
+
console.warn(`[scene-dispatch] Round-robin close failed for ${r.name}: ${e.message}`);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
if (stoppedNames.length) {
|
|
1381
|
+
console.log(`[scene-dispatch] Round-robin closed: [${stoppedNames.join(',')}] — next launch picks sibling`);
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
// Sort offline by last_command_assigned_at ASC (most idle first) so
|
|
1386
|
+
// the launcher picks the round-robin partner, not the one that just
|
|
1387
|
+
// finished. API populates last_command_assigned_at on every claim,
|
|
1388
|
+
// so this naturally implements turn-taking across siblings.
|
|
1389
|
+
stillOffline = stillOffline.slice().sort((a, b) => {
|
|
1390
|
+
const ta = a.last_command_assigned_at ? new Date(a.last_command_assigned_at).getTime() : 0;
|
|
1391
|
+
const tb = b.last_command_assigned_at ? new Date(b.last_command_assigned_at).getTime() : 0;
|
|
1392
|
+
return ta - tb;
|
|
1393
|
+
});
|
|
1394
|
+
|
|
1347
1395
|
// Launch policy: STRICT parallel_limit cap on physical launches.
|
|
1348
1396
|
// With pc2.parallel_limit=1 + 2 renderers (veo03/veo04 share same Veo
|
|
1349
1397
|
// Google account), only ONE of them is launched at any time. The
|