channel-worker 2.5.5 → 2.5.6

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.
@@ -139,6 +139,26 @@ class CommandPoller {
139
139
  }
140
140
  // Strip the '_pw' suffix to derive the script name (upload_youtube_pw → upload_youtube).
141
141
  const scriptName = command.type.replace(/_pw$/, '');
142
+
143
+ // PER-PROFILE MUTEX — two _pw scripts can't share the same NST profile.
144
+ // The NST browser is launched once and shared via CDP; concurrent
145
+ // page.goto / navigation calls from sibling scripts abort each other
146
+ // (saw `net::ERR_ABORTED` on FB while YT was navigating during the same
147
+ // publish click). Different profiles still run in parallel — this lock
148
+ // only serializes within a profile. Wait up to 30 min with 5s polling
149
+ // (upload typically 1-3 min); stale-cleanup picks up zombies separately.
150
+ if (!this._pwInFlight) this._pwInFlight = new Map();
151
+ const MUTEX_MAX_WAIT_MS = 30 * 60 * 1000;
152
+ const waitStart = Date.now();
153
+ while (this._pwInFlight.has(profileId)) {
154
+ if (Date.now() - waitStart > MUTEX_MAX_WAIT_MS) {
155
+ await this.api.updateCommand(command._id, { status: 'failed', error: `pw mutex timeout — profile ${profileId} busy with ${this._pwInFlight.get(profileId)} for >30min` });
156
+ return;
157
+ }
158
+ console.log(`[commands/pw] ${command.type} waiting — profile ${profileId} busy with ${this._pwInFlight.get(profileId)}`);
159
+ await new Promise(r => setTimeout(r, 5000));
160
+ }
161
+ this._pwInFlight.set(profileId, command.type);
142
162
  console.log(`[commands/pw] ${command.type} → scripts/${scriptName}.js (profile=${profileId})`);
143
163
 
144
164
  // Lazy-init NST manager (same pattern as the other handlers).
@@ -177,6 +197,10 @@ class CommandPoller {
177
197
  } catch (err) {
178
198
  console.error(`[commands/pw] ${command.type} failed: ${err.message}`);
179
199
  await this.api.postCommandResult(command._id, { status: 'failed', error: String(err.message || err).slice(0, 500) });
200
+ } finally {
201
+ // Always release the per-profile mutex — even on throw — or sibling
202
+ // pw cmds for the same profile would hang forever.
203
+ if (this._pwInFlight) this._pwInFlight.delete(profileId);
180
204
  }
181
205
  }
182
206
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "channel-worker",
3
- "version": "2.5.5",
3
+ "version": "2.5.6",
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": {