channel-worker 2.3.2 → 2.3.4

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/api-client.js CHANGED
@@ -29,10 +29,11 @@ class ApiClient {
29
29
  return this.request('POST', '/workers/register', workerData);
30
30
  }
31
31
 
32
- async heartbeat(workerId, version, extensionVersion) {
32
+ async heartbeat(workerId, version, extensionVersion, ccExtensionVersion) {
33
33
  const body = { worker_id: workerId };
34
34
  if (version) body.version = version;
35
35
  if (extensionVersion) body.extension_version = extensionVersion;
36
+ if (ccExtensionVersion) body.cc_extension_version = ccExtensionVersion;
36
37
  return this.request('POST', '/workers/heartbeat', body);
37
38
  }
38
39
 
@@ -1207,14 +1207,25 @@ class CommandPoller {
1207
1207
  } catch {}
1208
1208
  }
1209
1209
 
1210
- // 4. Check queued commands
1211
- const queueCount = await this.api.getSceneQueueCount();
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. Launch new profiles up to parallel limit (recompute offline after recovery)
1215
- const parallelLimit = parseInt(await this.api.getSetting('veo3_parallel_limit')) || 1;
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)}]`);
1218
1229
 
1219
1230
  // Count how many running profiles are actually free (no commands)
1220
1231
  let freeRunning = 0;
@@ -1316,7 +1327,8 @@ class CommandPoller {
1316
1327
  if (running.length === 0) return;
1317
1328
 
1318
1329
  // Check if there are any queued commands — if so, don't close anything
1319
- const queueCount = await this.api.getSceneQueueCount();
1330
+ const qi = await this.api.getSceneQueueCount();
1331
+ const queueCount = typeof qi === 'number' ? qi : (qi?.total || 0);
1320
1332
  if (queueCount > 0) return;
1321
1333
 
1322
1334
  for (const browser of running) {
package/lib/heartbeat.js CHANGED
@@ -1,6 +1,19 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
1
4
  const { getLocalVersion } = require('./updater');
2
5
  const { getLocalExtensionVersion } = require('./extension-updater');
3
6
 
7
+ function readCcExtensionVersion(config) {
8
+ try {
9
+ const dir = config.content_creator_ext_path || path.join(os.homedir(), 'content-creator-ext');
10
+ const manifest = JSON.parse(fs.readFileSync(path.join(dir, 'manifest.json'), 'utf8'));
11
+ return manifest.version || null;
12
+ } catch {
13
+ return null;
14
+ }
15
+ }
16
+
4
17
  class Heartbeat {
5
18
  constructor(api, workerId, intervalMs = 30000, config = {}) {
6
19
  this.api = api;
@@ -26,7 +39,8 @@ class Heartbeat {
26
39
  try {
27
40
  const version = getLocalVersion();
28
41
  const extVersion = getLocalExtensionVersion(this.config.extension_path);
29
- await this.api.heartbeat(this.workerId, version, extVersion);
42
+ const ccExtVersion = readCcExtensionVersion(this.config);
43
+ await this.api.heartbeat(this.workerId, version, extVersion, ccExtVersion);
30
44
  } catch (err) {
31
45
  console.error(`[heartbeat] Failed: ${err.message}`);
32
46
  }
@@ -66,7 +66,16 @@ class NstManager {
66
66
 
67
67
  // Create profile if not exists, return profileId
68
68
  async ensureProfile(name, options = {}) {
69
- const existing = await this.findProfile(name);
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({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "channel-worker",
3
- "version": "2.3.2",
3
+ "version": "2.3.4",
4
4
  "description": "Channel Manager worker daemon — runs on remote machines to execute video pipeline jobs",
5
5
  "main": "lib/daemon.js",
6
6
  "bin": {