neex 0.6.65 → 0.6.67
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/dist/src/commands/start-commands.js +10 -24
- package/dist/src/start-manager.js +83 -83
- package/package.json +1 -1
|
@@ -10,7 +10,6 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
10
10
|
const figures_1 = __importDefault(require("figures"));
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
12
|
const fs_1 = __importDefault(require("fs"));
|
|
13
|
-
const os_1 = __importDefault(require("os"));
|
|
14
13
|
function addStartCommands(program) {
|
|
15
14
|
let startManager = null;
|
|
16
15
|
// Production start command
|
|
@@ -20,7 +19,7 @@ function addStartCommands(program) {
|
|
|
20
19
|
.option('-d, --dir <directory>', 'Working directory', process.cwd())
|
|
21
20
|
.option('-e, --env <file>', 'Environment file to load', '.env')
|
|
22
21
|
.option('-p, --port <port>', 'Port number', parseInt)
|
|
23
|
-
.option('-w, --workers <count>', 'Number of worker processes
|
|
22
|
+
.option('-w, --workers <count>', 'Number of worker processes', parseInt, 1)
|
|
24
23
|
.option('-v, --verbose', 'Verbose output')
|
|
25
24
|
.option('--watch', 'Watch for changes and restart (development mode)')
|
|
26
25
|
.option('--no-health', 'Disable health check endpoint')
|
|
@@ -89,18 +88,6 @@ function addStartCommands(program) {
|
|
|
89
88
|
// Environment detection
|
|
90
89
|
const isDevelopment = options.watch || process.env.NODE_ENV === 'development';
|
|
91
90
|
const isProduction = !isDevelopment;
|
|
92
|
-
const cpuCount = os_1.default.cpus().length;
|
|
93
|
-
// Smart worker allocation
|
|
94
|
-
let workers = options.workers;
|
|
95
|
-
if (!workers) {
|
|
96
|
-
if (isDevelopment) {
|
|
97
|
-
workers = 1;
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
// For production, use CPU count but cap at reasonable limit
|
|
101
|
-
workers = Math.min(cpuCount, 4); // Reduced from 8 to 4 for better resource management
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
91
|
const healthCheck = options.health !== false;
|
|
105
92
|
const defaultPort = parseInt(process.env.PORT || '8000');
|
|
106
93
|
const port = options.port || defaultPort;
|
|
@@ -110,14 +97,14 @@ function addStartCommands(program) {
|
|
|
110
97
|
}
|
|
111
98
|
// Startup logging
|
|
112
99
|
const mode = isDevelopment ? 'development' : 'production';
|
|
113
|
-
const clusterInfo = workers > 1 ? ` (${workers} workers)` : '';
|
|
100
|
+
const clusterInfo = options.workers > 1 ? ` (${options.workers} workers)` : '';
|
|
114
101
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.play)} Starting ${mode} server${clusterInfo}`, 'info');
|
|
115
102
|
if (options.verbose) {
|
|
116
103
|
logger_manager_js_1.loggerManager.printLine(`File: ${path_1.default.relative(process.cwd(), resolvedFile)}`);
|
|
117
104
|
logger_manager_js_1.loggerManager.printLine(`Working Directory: ${options.dir}`);
|
|
118
105
|
logger_manager_js_1.loggerManager.printLine(`Environment: ${process.env.NODE_ENV}`);
|
|
119
106
|
logger_manager_js_1.loggerManager.printLine(`Port: ${port}`);
|
|
120
|
-
logger_manager_js_1.loggerManager.printLine(`Workers: ${workers}`);
|
|
107
|
+
logger_manager_js_1.loggerManager.printLine(`Workers: ${options.workers}`);
|
|
121
108
|
if (healthCheck) {
|
|
122
109
|
logger_manager_js_1.loggerManager.printLine(`Health Check: http://localhost:${options.healthPort}/health`);
|
|
123
110
|
}
|
|
@@ -126,16 +113,15 @@ function addStartCommands(program) {
|
|
|
126
113
|
file: resolvedFile,
|
|
127
114
|
workingDir: options.dir,
|
|
128
115
|
envFile: options.env,
|
|
129
|
-
port,
|
|
130
|
-
workers,
|
|
131
|
-
memoryLimit:
|
|
132
|
-
logLevel: options.verbose ? '
|
|
133
|
-
color:
|
|
116
|
+
port: options.port,
|
|
117
|
+
workers: options.workers,
|
|
118
|
+
memoryLimit: options.maxMemory,
|
|
119
|
+
logLevel: options.verbose ? 'verbose' : 'info',
|
|
120
|
+
color: true,
|
|
134
121
|
verbose: options.verbose,
|
|
135
122
|
watch: options.watch,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
restartDelay: isProduction ? 1000 : 500,
|
|
123
|
+
maxCrashes: 5,
|
|
124
|
+
restartDelay: 2000,
|
|
139
125
|
healthCheck,
|
|
140
126
|
healthPort: options.healthPort,
|
|
141
127
|
gracefulTimeout: options.gracefulTimeout,
|
|
@@ -159,97 +159,98 @@ class StartManager {
|
|
|
159
159
|
this.log(`Process started (PID: ${this.masterProcess.pid}, Port: ${port})`);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
});
|
|
224
|
-
// Wait for worker to be ready
|
|
225
|
-
await new Promise((resolve, reject) => {
|
|
226
|
-
const timeout = setTimeout(() => {
|
|
227
|
-
resolve(); // Don't reject, assume it's ready
|
|
228
|
-
}, 5000);
|
|
229
|
-
workerProcess.on('message', (message) => {
|
|
162
|
+
startWorker(workerId) {
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
var _a, _b;
|
|
165
|
+
const nodeArgs = this.getNodeArgs();
|
|
166
|
+
const port = this.options.port || 8000;
|
|
167
|
+
const env = {
|
|
168
|
+
...process.env,
|
|
169
|
+
NODE_ENV: process.env.NODE_ENV || 'production',
|
|
170
|
+
WORKER_ID: workerId.toString(),
|
|
171
|
+
PORT: port.toString(),
|
|
172
|
+
CLUSTER_WORKER: 'true',
|
|
173
|
+
FORCE_COLOR: this.options.color ? '1' : '0',
|
|
174
|
+
NODE_OPTIONS: '--no-deprecation'
|
|
175
|
+
};
|
|
176
|
+
const workerProcess = (0, child_process_1.fork)(this.options.file, [], {
|
|
177
|
+
cwd: this.options.workingDir,
|
|
178
|
+
env,
|
|
179
|
+
execArgv: nodeArgs,
|
|
180
|
+
silent: true
|
|
181
|
+
});
|
|
182
|
+
const workerInfo = {
|
|
183
|
+
process: workerProcess,
|
|
184
|
+
pid: workerProcess.pid,
|
|
185
|
+
restarts: 0,
|
|
186
|
+
startTime: new Date(),
|
|
187
|
+
id: workerId,
|
|
188
|
+
port: port
|
|
189
|
+
};
|
|
190
|
+
this.workers.set(workerId, workerInfo);
|
|
191
|
+
let isReady = false;
|
|
192
|
+
const readinessTimeout = setTimeout(() => {
|
|
193
|
+
if (!isReady) {
|
|
194
|
+
workerProcess.kill();
|
|
195
|
+
reject(new Error(`Worker ${workerId} failed to become ready within 15s.`));
|
|
196
|
+
}
|
|
197
|
+
}, 15000);
|
|
198
|
+
const cleanupReadinessListeners = () => {
|
|
199
|
+
var _a;
|
|
200
|
+
clearTimeout(readinessTimeout);
|
|
201
|
+
(_a = workerProcess.stdout) === null || _a === void 0 ? void 0 : _a.removeListener('data', onDataForReady);
|
|
202
|
+
workerProcess.removeListener('message', onMessageForReady);
|
|
203
|
+
};
|
|
204
|
+
const onReady = () => {
|
|
205
|
+
if (isReady)
|
|
206
|
+
return;
|
|
207
|
+
isReady = true;
|
|
208
|
+
cleanupReadinessListeners();
|
|
209
|
+
if (this.options.verbose) {
|
|
210
|
+
this.log(`Worker ${workerId} is ready (PID: ${workerProcess.pid})`);
|
|
211
|
+
}
|
|
212
|
+
resolve(workerInfo);
|
|
213
|
+
};
|
|
214
|
+
const onDataForReady = (data) => {
|
|
215
|
+
const message = data.toString();
|
|
216
|
+
const prefix = chalk_1.default.dim(`[Worker ${workerId}] `);
|
|
217
|
+
process.stdout.write(prefix + message);
|
|
218
|
+
if (/listening|ready|running on port|local:/i.test(message)) {
|
|
219
|
+
onReady();
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
const onMessageForReady = (message) => {
|
|
230
223
|
if (message && message.type === 'ready') {
|
|
231
|
-
|
|
232
|
-
resolve();
|
|
224
|
+
onReady();
|
|
233
225
|
}
|
|
226
|
+
};
|
|
227
|
+
(_a = workerProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', onDataForReady);
|
|
228
|
+
(_b = workerProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
229
|
+
const prefix = chalk_1.default.red.dim(`[Worker ${workerId}] `);
|
|
230
|
+
process.stderr.write(prefix + data.toString());
|
|
234
231
|
});
|
|
232
|
+
workerProcess.on('message', onMessageForReady);
|
|
235
233
|
workerProcess.on('error', (error) => {
|
|
236
|
-
|
|
237
|
-
|
|
234
|
+
if (!isReady) {
|
|
235
|
+
cleanupReadinessListeners();
|
|
236
|
+
reject(error);
|
|
237
|
+
}
|
|
238
|
+
this.log(`Worker ${workerId} error: ${error.message}`, 'error');
|
|
238
239
|
});
|
|
239
|
-
workerProcess.on('exit', (code) => {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
reject(new Error(`Worker ${workerId} exited with code ${code}
|
|
240
|
+
workerProcess.on('exit', (code, signal) => {
|
|
241
|
+
if (!isReady) {
|
|
242
|
+
cleanupReadinessListeners();
|
|
243
|
+
reject(new Error(`Worker ${workerId} exited with code ${code} before becoming ready.`));
|
|
243
244
|
}
|
|
244
245
|
else {
|
|
245
|
-
|
|
246
|
+
this.workers.delete(workerId);
|
|
247
|
+
if (!this.isShuttingDown && code !== 0 && signal !== 'SIGTERM') {
|
|
248
|
+
this.log(`Worker ${workerId} crashed (code: ${code}, signal: ${signal})`, 'error');
|
|
249
|
+
this.restartWorker(workerId);
|
|
250
|
+
}
|
|
246
251
|
}
|
|
247
252
|
});
|
|
248
253
|
});
|
|
249
|
-
if (this.options.verbose) {
|
|
250
|
-
this.log(`Worker ${workerId} started (PID: ${workerProcess.pid})`);
|
|
251
|
-
}
|
|
252
|
-
return workerInfo;
|
|
253
254
|
}
|
|
254
255
|
async restartWorker(workerId) {
|
|
255
256
|
const workerInfo = this.workers.get(workerId);
|
|
@@ -308,9 +309,8 @@ class StartManager {
|
|
|
308
309
|
}
|
|
309
310
|
catch (error) {
|
|
310
311
|
this.log(`Failed to start some workers: ${error.message}`, 'error');
|
|
311
|
-
// Continue with successfully started workers
|
|
312
312
|
if (this.workers.size > 0) {
|
|
313
|
-
this.log(`${chalk_1.default.
|
|
313
|
+
this.log(`${chalk_1.default.yellow(figures_1.default.warning)} Server partially ready on port ${this.options.port || 8000} (${this.workers.size} workers)`);
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
316
|
}
|