channel-worker 2.0.3 → 2.1.0

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.
@@ -1166,75 +1166,38 @@ class CommandPoller {
1166
1166
  });
1167
1167
  const offlineRenderers = renderers.filter(r => !runningRenderers.includes(r));
1168
1168
 
1169
- // 6. Pick target profile launch new if under limit, else assign to running
1170
- let target = null;
1169
+ // 6. Launch profiles up to parallel limit
1171
1170
  console.log(`[scene-dispatch] running=${runningRenderers.length}/${parallelLimit} offline=${offlineRenderers.length} queue=${queueCount} names=[${runningRenderers.map(r=>r.name)}]`);
1172
1171
 
1173
- if (runningRenderers.length < parallelLimit && offlineRenderers.length > 0) {
1174
- // Under limit launch a new profile first
1175
- target = offlineRenderers[0];
1176
- console.log(`[scene-dispatch] Launching ${target.name} (running: ${runningRenderers.length}/${parallelLimit})`);
1172
+ const neededLaunches = Math.min(parallelLimit - runningRenderers.length, offlineRenderers.length, queueCount);
1173
+ for (let li = 0; li < neededLaunches; li++) {
1174
+ const toLaunch = offlineRenderers[li];
1175
+ console.log(`[scene-dispatch] Launching ${toLaunch.name} (running: ${runningRenderers.length + li}/${parallelLimit})`);
1177
1176
  try {
1178
- await this.nst.ensureProfile(target.nst_profile_id, { os: target.os || 'windows', proxy: target.proxy || null });
1179
-
1180
- const path = require('path');
1181
- const os_mod = require('os');
1182
- const defaultCCExtPath = path.join(os_mod.homedir(), 'content-creator-ext');
1183
- const baseExtPath = this.config.content_creator_ext_path || defaultCCExtPath;
1184
- await this._ensureContentCreatorExt(baseExtPath);
1185
-
1186
- // Create unique ext dir per profile + version (forces Chromium to reload SW)
1187
- let extensionPath = baseExtPath;
1188
- const fs = require('fs');
1189
- const extVersion = (() => { try { return JSON.parse(fs.readFileSync(path.join(baseExtPath, 'manifest.json'), 'utf8')).version; } catch { return '0'; } })();
1190
- const uniqueExtPath = baseExtPath + '-' + target.nst_profile_id + '-v' + extVersion;
1191
- try {
1192
- // Clean old version dirs for this profile
1193
- const parent = path.dirname(baseExtPath);
1194
- const prefix = path.basename(baseExtPath) + '-' + target.nst_profile_id;
1195
- try {
1196
- fs.readdirSync(parent)
1197
- .filter(d => d.startsWith(prefix) && d !== path.basename(uniqueExtPath))
1198
- .forEach(d => { try { fs.rmSync(path.join(parent, d), { recursive: true }); } catch {} });
1199
- } catch {}
1200
- if (fs.existsSync(uniqueExtPath)) fs.rmSync(uniqueExtPath, { recursive: true });
1201
- fs.mkdirSync(uniqueExtPath, { recursive: true });
1202
- fs.cpSync(baseExtPath, uniqueExtPath, { recursive: true });
1203
- fs.writeFileSync(path.join(uniqueExtPath, 'config.json'), JSON.stringify({
1204
- channelManagerApi: this.api.baseUrl,
1205
- profileId: target.nst_profile_id,
1206
- workerToken: this.config.worker_token || '',
1207
- workerType: 'veo3',
1208
- }));
1209
- extensionPath = uniqueExtPath;
1210
- } catch (e) {
1211
- console.warn(`[scene-dispatch] Ext dir failed: ${e.message}, using base`);
1212
- }
1213
-
1214
- await this.nst.launchProfile(target.nst_profile_id, { proxy: target.proxy || null, extensionPath });
1215
- console.log(`[scene-dispatch] ${target.name} launched`);
1177
+ await this._launchRendererProfile(toLaunch);
1178
+ runningRenderers.push(toLaunch); // now considered running
1179
+ console.log(`[scene-dispatch] ${toLaunch.name} launched`);
1216
1180
  } catch (err) {
1217
- console.error(`[scene-dispatch] Failed to launch ${target.name}: ${err.message}`);
1218
- target = runningRenderers[0] || null; // fallback to running
1181
+ console.error(`[scene-dispatch] Failed to launch ${toLaunch.name}: ${err.message}`);
1219
1182
  }
1220
1183
  }
1221
1184
 
1222
- // Fallback: assign to least loaded running renderer
1223
- if (!target && runningRenderers.length > 0) {
1224
- target = runningRenderers[0]; // extension processes commands sequentially per profile
1225
- }
1226
-
1227
- if (!target) {
1228
- // No renderers available at all — wait for next cycle
1185
+ if (runningRenderers.length === 0) {
1229
1186
  this._dispatching = false;
1230
1187
  return;
1231
1188
  }
1232
1189
 
1233
- // 7. Claim command and assign to profile
1234
- const cmd = await this.api.sceneDispatch(target.nst_profile_id);
1235
- if (cmd) {
1190
+ // 7. Assign queued commands round-robin across running renderers
1191
+ let assigned = 0;
1192
+ for (let qi = 0; qi < queueCount; qi++) {
1193
+ const target = runningRenderers[qi % runningRenderers.length];
1194
+ const cmd = await this.api.sceneDispatch(target.nst_profile_id);
1195
+ if (!cmd) break; // queue empty
1236
1196
  this._profileLastActivity[target.nst_profile_id] = Date.now();
1237
- console.log(`[scene-dispatch] Assigned ${cmd.type} → ${target.name} (queue: ${queueCount - 1})`);
1197
+ assigned++;
1198
+ }
1199
+ if (assigned > 0) {
1200
+ console.log(`[scene-dispatch] Assigned ${assigned} commands across ${runningRenderers.length} renderers`);
1238
1201
  }
1239
1202
  } catch (err) {
1240
1203
  console.error(`[scene-dispatch] Error: ${err.message}`);
@@ -1242,6 +1205,44 @@ class CommandPoller {
1242
1205
  this._dispatching = false;
1243
1206
  }
1244
1207
 
1208
+ async _launchRendererProfile(renderer) {
1209
+ await this.nst.ensureProfile(renderer.nst_profile_id, { os: renderer.os || 'windows', proxy: renderer.proxy || null });
1210
+
1211
+ const path = require('path');
1212
+ const os_mod = require('os');
1213
+ const fs = require('fs');
1214
+ const defaultCCExtPath = path.join(os_mod.homedir(), 'content-creator-ext');
1215
+ const baseExtPath = this.config.content_creator_ext_path || defaultCCExtPath;
1216
+ await this._ensureContentCreatorExt(baseExtPath);
1217
+
1218
+ let extensionPath = baseExtPath;
1219
+ const extVersion = (() => { try { return JSON.parse(fs.readFileSync(path.join(baseExtPath, 'manifest.json'), 'utf8')).version; } catch { return '0'; } })();
1220
+ const uniqueExtPath = baseExtPath + '-' + renderer.nst_profile_id + '-v' + extVersion;
1221
+ try {
1222
+ const parent = path.dirname(baseExtPath);
1223
+ const prefix = path.basename(baseExtPath) + '-' + renderer.nst_profile_id;
1224
+ try {
1225
+ fs.readdirSync(parent)
1226
+ .filter(d => d.startsWith(prefix) && d !== path.basename(uniqueExtPath))
1227
+ .forEach(d => { try { fs.rmSync(path.join(parent, d), { recursive: true }); } catch {} });
1228
+ } catch {}
1229
+ if (fs.existsSync(uniqueExtPath)) fs.rmSync(uniqueExtPath, { recursive: true });
1230
+ fs.mkdirSync(uniqueExtPath, { recursive: true });
1231
+ fs.cpSync(baseExtPath, uniqueExtPath, { recursive: true });
1232
+ fs.writeFileSync(path.join(uniqueExtPath, 'config.json'), JSON.stringify({
1233
+ channelManagerApi: this.api.baseUrl,
1234
+ profileId: renderer.nst_profile_id,
1235
+ workerToken: this.config.worker_token || '',
1236
+ workerType: 'veo3',
1237
+ }));
1238
+ extensionPath = uniqueExtPath;
1239
+ } catch (e) {
1240
+ console.warn(`[scene-dispatch] Ext dir failed: ${e.message}, using base`);
1241
+ }
1242
+
1243
+ await this.nst.launchProfile(renderer.nst_profile_id, { proxy: renderer.proxy || null, extensionPath });
1244
+ }
1245
+
1245
1246
  // ─── Profile Timeout ───────────────────────────────────────────────────────
1246
1247
  // Close profiles that have been idle (no commands assigned) for too long.
1247
1248
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "channel-worker",
3
- "version": "2.0.3",
3
+ "version": "2.1.0",
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": {