channel-worker 2.3.0 → 2.3.2
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/cache-server.js +65 -13
- package/lib/command-poller.js +1 -0
- package/package.json +1 -1
package/lib/cache-server.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const http = require('http');
|
|
15
15
|
const url = require('url');
|
|
16
|
+
const { execSync } = require('child_process');
|
|
16
17
|
|
|
17
18
|
class CacheServer {
|
|
18
19
|
constructor(api, options = {}) {
|
|
@@ -110,25 +111,76 @@ class CacheServer {
|
|
|
110
111
|
res.end(JSON.stringify({ success: false, message: 'not found' }));
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
114
|
+
// Find PID(s) holding our port and kill them. Cross-platform best-effort.
|
|
115
|
+
// Used when bind fails with EADDRINUSE — typically a leaked previous daemon.
|
|
116
|
+
_killPortHolder() {
|
|
117
|
+
try {
|
|
118
|
+
if (process.platform === 'win32') {
|
|
119
|
+
// netstat columns: Proto Local Foreign State PID
|
|
120
|
+
const out = execSync(`netstat -ano -p TCP | findstr :${this.port} | findstr LISTENING`,
|
|
121
|
+
{ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
122
|
+
const pids = new Set();
|
|
123
|
+
for (const line of out.split('\n')) {
|
|
124
|
+
const m = line.trim().match(/\s(\d+)\s*$/);
|
|
125
|
+
if (m) pids.add(m[1]);
|
|
122
126
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
for (const pid of pids) {
|
|
128
|
+
if (Number(pid) === process.pid) continue;
|
|
129
|
+
console.log(`[cache-server] Killing leaked PID ${pid} holding port ${this.port}`);
|
|
130
|
+
try { execSync(`taskkill /PID ${pid} /F`, { stdio: 'ignore' }); } catch {}
|
|
131
|
+
}
|
|
132
|
+
return pids.size;
|
|
133
|
+
}
|
|
134
|
+
// mac/linux
|
|
135
|
+
const out = execSync(`lsof -ti:${this.port} -sTCP:LISTEN`,
|
|
136
|
+
{ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
137
|
+
const pids = out.split('\n').map(s => s.trim()).filter(Boolean);
|
|
138
|
+
for (const pid of pids) {
|
|
139
|
+
if (Number(pid) === process.pid) continue;
|
|
140
|
+
console.log(`[cache-server] Killing leaked PID ${pid} holding port ${this.port}`);
|
|
141
|
+
try { execSync(`kill -9 ${pid}`, { stdio: 'ignore' }); } catch {}
|
|
142
|
+
}
|
|
143
|
+
return pids.length;
|
|
144
|
+
} catch {
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
_bindOnce() {
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
const server = http.createServer((req, res) => this._handleRequest(req, res));
|
|
152
|
+
server.on('error', (err) => reject(err));
|
|
153
|
+
server.listen(this.port, this.host, () => {
|
|
154
|
+
this.server = server;
|
|
127
155
|
resolve();
|
|
128
156
|
});
|
|
129
157
|
});
|
|
130
158
|
}
|
|
131
159
|
|
|
160
|
+
async start() {
|
|
161
|
+
try {
|
|
162
|
+
await this._bindOnce();
|
|
163
|
+
} catch (err) {
|
|
164
|
+
if (err.code !== 'EADDRINUSE') throw err;
|
|
165
|
+
console.warn(`[cache-server] Port ${this.port} busy — trying to kill leaked holder...`);
|
|
166
|
+
const killed = this._killPortHolder();
|
|
167
|
+
if (killed === 0) {
|
|
168
|
+
console.error(`[cache-server] No leaked process found for port ${this.port}. ` +
|
|
169
|
+
`Maybe TIME_WAIT — wait 30-60s and retry.`);
|
|
170
|
+
throw err;
|
|
171
|
+
}
|
|
172
|
+
// Wait for OS to release the port after kill, then retry once
|
|
173
|
+
await new Promise(r => setTimeout(r, 500));
|
|
174
|
+
try {
|
|
175
|
+
await this._bindOnce();
|
|
176
|
+
} catch (err2) {
|
|
177
|
+
console.error(`[cache-server] Still cannot bind ${this.port} after killing leaked PIDs.`);
|
|
178
|
+
throw err2;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
console.log(`[cache-server] Listening on http://${this.host}:${this.port} (max ${this.maxEntries} entries)`);
|
|
182
|
+
}
|
|
183
|
+
|
|
132
184
|
stop() {
|
|
133
185
|
if (this.server) {
|
|
134
186
|
this.server.close();
|
package/lib/command-poller.js
CHANGED
|
@@ -1293,6 +1293,7 @@ class CommandPoller {
|
|
|
1293
1293
|
profileId: renderer.nst_profile_id,
|
|
1294
1294
|
workerToken: this.config.worker_token || '',
|
|
1295
1295
|
workerType: 'veo3',
|
|
1296
|
+
daemonUrl: this.config.daemon_url || '',
|
|
1296
1297
|
}));
|
|
1297
1298
|
extensionPath = uniqueExtPath;
|
|
1298
1299
|
} catch (e) {
|