channel-worker 2.3.3 → 2.3.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 +45 -6
- package/lib/nst-manager.js +11 -2
- package/package.json +1 -1
package/lib/command-poller.js
CHANGED
|
@@ -1207,14 +1207,52 @@ class CommandPoller {
|
|
|
1207
1207
|
} catch {}
|
|
1208
1208
|
}
|
|
1209
1209
|
|
|
1210
|
-
// 4. Check queued commands
|
|
1211
|
-
const
|
|
1210
|
+
// 4. Check queued commands — new API returns {total, flowkit_count, dom_count}
|
|
1211
|
+
const queueInfo = await this.api.getSceneQueueCount();
|
|
1212
|
+
const queueCount = typeof queueInfo === 'number' ? queueInfo : (queueInfo?.total || 0);
|
|
1213
|
+
const flowkitQ = typeof queueInfo === 'number' ? 0 : (queueInfo?.flowkit_count || 0);
|
|
1214
|
+
const domQ = typeof queueInfo === 'number' ? queueCount : (queueInfo?.dom_count || 0);
|
|
1212
1215
|
if (!queueCount) { this._dispatching = false; return; }
|
|
1213
1216
|
|
|
1214
|
-
// 5.
|
|
1215
|
-
|
|
1217
|
+
// 5. Pick the right parallel limit based on queue composition
|
|
1218
|
+
// - queue toàn flowkit → dùng flowkit_max_concurrent
|
|
1219
|
+
// - queue toàn DOM → dùng veo3_parallel_limit
|
|
1220
|
+
// - mixed (hiếm) → dùng max của 2 để không bottleneck nhánh nào
|
|
1221
|
+
const flowkitLimit = parseInt(await this.api.getSetting('flowkit_max_concurrent')) || 5;
|
|
1222
|
+
const veo3Limit = parseInt(await this.api.getSetting('veo3_parallel_limit')) || 1;
|
|
1223
|
+
let parallelLimit;
|
|
1224
|
+
if (flowkitQ > 0 && domQ === 0) parallelLimit = flowkitLimit;
|
|
1225
|
+
else if (domQ > 0 && flowkitQ === 0) parallelLimit = veo3Limit;
|
|
1226
|
+
else parallelLimit = Math.max(flowkitLimit, veo3Limit);
|
|
1216
1227
|
const stillOffline = renderers.filter(r => !runningRenderers.includes(r));
|
|
1217
|
-
console.log(`[scene-dispatch] running=${runningRenderers.length}/${parallelLimit} offline=${stillOffline.length} queue=${queueCount} names=[${runningRenderers.map(r=>r.name)}]`);
|
|
1228
|
+
console.log(`[scene-dispatch] running=${runningRenderers.length}/${parallelLimit} (flowkit=${flowkitQ} dom=${domQ}) offline=${stillOffline.length} queue=${queueCount} names=[${runningRenderers.map(r=>r.name)}]`);
|
|
1229
|
+
|
|
1230
|
+
// 5b. Close excess profiles — when parallelLimit drops (e.g., after a DOM→FlowKit
|
|
1231
|
+
// switch), idle profiles over the cap should shut down instead of staying open
|
|
1232
|
+
// and getting throttled at /flowkit/claim-command.
|
|
1233
|
+
if (runningRenderers.length > parallelLimit) {
|
|
1234
|
+
const excess = runningRenderers.length - parallelLimit;
|
|
1235
|
+
const idleRenderers = [];
|
|
1236
|
+
for (const r of runningRenderers) {
|
|
1237
|
+
try {
|
|
1238
|
+
const c = await this.api.rendererHasCommands(r.nst_profile_id);
|
|
1239
|
+
if (c === 0) idleRenderers.push(r);
|
|
1240
|
+
} catch {}
|
|
1241
|
+
}
|
|
1242
|
+
const toClose = idleRenderers.slice(0, excess);
|
|
1243
|
+
for (const r of toClose) {
|
|
1244
|
+
console.log(`[scene-dispatch] Closing excess profile ${r.name} (over cap ${parallelLimit})`);
|
|
1245
|
+
try {
|
|
1246
|
+
await this.nst.stopProfile(r.nst_profile_id);
|
|
1247
|
+
delete this._profileLastActivity[r.nst_profile_id];
|
|
1248
|
+
if (r.name) delete this._profileLastActivity[r.name.toLowerCase()];
|
|
1249
|
+
const idx = runningRenderers.indexOf(r);
|
|
1250
|
+
if (idx >= 0) runningRenderers.splice(idx, 1);
|
|
1251
|
+
} catch (e) {
|
|
1252
|
+
console.warn(`[scene-dispatch] Failed to close excess ${r.name}: ${e.message}`);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1218
1256
|
|
|
1219
1257
|
// Count how many running profiles are actually free (no commands)
|
|
1220
1258
|
let freeRunning = 0;
|
|
@@ -1316,7 +1354,8 @@ class CommandPoller {
|
|
|
1316
1354
|
if (running.length === 0) return;
|
|
1317
1355
|
|
|
1318
1356
|
// Check if there are any queued commands — if so, don't close anything
|
|
1319
|
-
const
|
|
1357
|
+
const qi = await this.api.getSceneQueueCount();
|
|
1358
|
+
const queueCount = typeof qi === 'number' ? qi : (qi?.total || 0);
|
|
1320
1359
|
if (queueCount > 0) return;
|
|
1321
1360
|
|
|
1322
1361
|
for (const browser of running) {
|
package/lib/nst-manager.js
CHANGED
|
@@ -66,7 +66,16 @@ class NstManager {
|
|
|
66
66
|
|
|
67
67
|
// Create profile if not exists, return profileId
|
|
68
68
|
async ensureProfile(name, options = {}) {
|
|
69
|
-
|
|
69
|
+
// Retry findProfile up to 3 times — Nstbrowser API can transiently return empty
|
|
70
|
+
let existing = null;
|
|
71
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
72
|
+
existing = await this.findProfile(name);
|
|
73
|
+
if (existing) break;
|
|
74
|
+
if (attempt < 3) {
|
|
75
|
+
console.log(`[nst] Profile "${name}" not found (attempt ${attempt}/3), retrying in 2s...`);
|
|
76
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
70
79
|
if (existing) {
|
|
71
80
|
console.log(`[nst] Profile "${name}" exists: ${existing}`);
|
|
72
81
|
// Set proxy on existing profile if provided
|
|
@@ -75,7 +84,7 @@ class NstManager {
|
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
const platform = (options.os || 'windows').toLowerCase() === 'mac' ? 'MacOS' : 'Windows';
|
|
78
|
-
console.log(`[nst] WARNING: Profile "${name}" NOT FOUND — creating new profile (${platform})...`);
|
|
87
|
+
console.log(`[nst] WARNING: Profile "${name}" NOT FOUND after 3 retries — creating new profile (${platform})...`);
|
|
79
88
|
const res = await this.api('/profiles', {
|
|
80
89
|
method: 'POST',
|
|
81
90
|
body: JSON.stringify({
|