channel-worker 2.1.7 → 2.2.1
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 +22 -14
- package/package.json +1 -1
package/lib/command-poller.js
CHANGED
|
@@ -1169,6 +1169,7 @@ class CommandPoller {
|
|
|
1169
1169
|
await this.api.resetRendererCommands(r.nst_profile_id);
|
|
1170
1170
|
await this._launchRendererProfile(r);
|
|
1171
1171
|
runningRenderers.push(r);
|
|
1172
|
+
this._profileLastActivity[r.nst_profile_id] = Date.now();
|
|
1172
1173
|
console.log(`[scene-dispatch] ${r.name} recovered (${cmdCount} commands reset)`);
|
|
1173
1174
|
} catch (err) {
|
|
1174
1175
|
console.error(`[scene-dispatch] Failed to recover ${r.name}: ${err.message}`);
|
|
@@ -1179,19 +1180,24 @@ class CommandPoller {
|
|
|
1179
1180
|
|
|
1180
1181
|
// 3b. Running profiles with stale heartbeat + PENDING commands → extension never started
|
|
1181
1182
|
// Only restart if commands are still "pending" (not "running" = extension picked up but busy)
|
|
1182
|
-
const HEARTBEAT_STALE =
|
|
1183
|
+
const HEARTBEAT_STALE = 60 * 1000; // 60s — extension heartbeats every 15s
|
|
1184
|
+
const LAUNCH_GRACE = 60 * 1000; // 60s grace period after launch for extension to init
|
|
1183
1185
|
const now = Date.now();
|
|
1184
1186
|
for (const r of [...runningRenderers]) {
|
|
1185
1187
|
try {
|
|
1186
|
-
// Only check profiles that have pending commands (not running = actively processing)
|
|
1187
1188
|
const cmdCount = await this.api.rendererHasCommands(r.nst_profile_id);
|
|
1188
1189
|
if (cmdCount === 0) continue;
|
|
1190
|
+
// Skip if recently launched (grace period for extension to init + first heartbeat)
|
|
1191
|
+
const lastLaunch = this._profileLastActivity[r.nst_profile_id] || 0;
|
|
1192
|
+
if (lastLaunch && (now - lastLaunch) < LAUNCH_GRACE) continue;
|
|
1189
1193
|
const hb = r.last_heartbeat ? new Date(r.last_heartbeat).getTime() : 0;
|
|
1190
|
-
if (hb && (now - hb) < HEARTBEAT_STALE) continue;
|
|
1194
|
+
if (hb && (now - hb) < HEARTBEAT_STALE) continue; // heartbeat fresh
|
|
1195
|
+
if (!hb && lastLaunch) continue; // never heartbeated but recently tracked — still in grace
|
|
1191
1196
|
console.log(`[scene-dispatch] Stuck: ${r.name} running but heartbeat stale (${hb ? Math.round((now - hb) / 1000) + 's' : 'never'}) — restarting`);
|
|
1192
1197
|
try {
|
|
1193
1198
|
await this.api.resetRendererCommands(r.nst_profile_id);
|
|
1194
1199
|
await this._launchRendererProfile(r, { forceRelaunch: true });
|
|
1200
|
+
this._profileLastActivity[r.nst_profile_id] = Date.now();
|
|
1195
1201
|
console.log(`[scene-dispatch] ${r.name} restarted`);
|
|
1196
1202
|
} catch (err) {
|
|
1197
1203
|
console.error(`[scene-dispatch] Failed to restart ${r.name}: ${err.message}`);
|
|
@@ -1214,7 +1220,8 @@ class CommandPoller {
|
|
|
1214
1220
|
console.log(`[scene-dispatch] Launching ${toLaunch.name} (running: ${runningRenderers.length + li}/${parallelLimit})`);
|
|
1215
1221
|
try {
|
|
1216
1222
|
await this._launchRendererProfile(toLaunch);
|
|
1217
|
-
runningRenderers.push(toLaunch);
|
|
1223
|
+
runningRenderers.push(toLaunch);
|
|
1224
|
+
this._profileLastActivity[toLaunch.nst_profile_id] = Date.now();
|
|
1218
1225
|
console.log(`[scene-dispatch] ${toLaunch.name} launched`);
|
|
1219
1226
|
} catch (err) {
|
|
1220
1227
|
console.error(`[scene-dispatch] Failed to launch ${toLaunch.name}: ${err.message}`);
|
|
@@ -1226,17 +1233,18 @@ class CommandPoller {
|
|
|
1226
1233
|
return;
|
|
1227
1234
|
}
|
|
1228
1235
|
|
|
1229
|
-
// 7. Assign
|
|
1236
|
+
// 7. Assign 1 command per free profile (no pending/running commands)
|
|
1230
1237
|
let assigned = 0;
|
|
1231
|
-
for (
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1238
|
+
for (const r of runningRenderers) {
|
|
1239
|
+
try {
|
|
1240
|
+
const cmdCount = await this.api.rendererHasCommands(r.nst_profile_id);
|
|
1241
|
+
if (cmdCount > 0) continue; // already has work
|
|
1242
|
+
const cmd = await this.api.sceneDispatch(r.nst_profile_id);
|
|
1243
|
+
if (!cmd) break; // queue empty
|
|
1244
|
+
this._profileLastActivity[r.nst_profile_id] = Date.now();
|
|
1245
|
+
assigned++;
|
|
1246
|
+
console.log(`[scene-dispatch] Assigned ${cmd.type} → ${r.name}`);
|
|
1247
|
+
} catch {}
|
|
1240
1248
|
}
|
|
1241
1249
|
} catch (err) {
|
|
1242
1250
|
console.error(`[scene-dispatch] Error: ${err.message}`);
|