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.
@@ -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 (default: auto)', parseInt)
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: isProduction ? '512M' : undefined,
132
- logLevel: options.verbose ? 'debug' : 'info',
133
- color: process.stdout.isTTY,
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
- maxMemory: options.maxMemory || (isProduction ? '1G' : undefined),
137
- maxCrashes: isProduction ? 3 : 10,
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
- async startWorker(workerId) {
163
- var _a, _b;
164
- const nodeArgs = this.getNodeArgs();
165
- const port = this.options.port || 8000;
166
- const env = {
167
- ...process.env,
168
- NODE_ENV: process.env.NODE_ENV || 'production',
169
- WORKER_ID: workerId.toString(),
170
- PORT: port.toString(),
171
- CLUSTER_WORKER: 'true',
172
- FORCE_COLOR: this.options.color ? '1' : '0',
173
- NODE_OPTIONS: '--no-deprecation'
174
- };
175
- const workerProcess = (0, child_process_1.fork)(this.options.file, [], {
176
- cwd: this.options.workingDir,
177
- env,
178
- execArgv: nodeArgs,
179
- silent: true
180
- });
181
- const workerInfo = {
182
- process: workerProcess,
183
- pid: workerProcess.pid,
184
- restarts: 0,
185
- startTime: new Date(),
186
- id: workerId,
187
- port: port
188
- };
189
- this.workers.set(workerId, workerInfo);
190
- // Handle worker output
191
- (_a = workerProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
192
- const message = data.toString().trim();
193
- // Suppress common startup messages from workers
194
- if (message &&
195
- !message.includes('[dotenv@') &&
196
- !message.includes('injecting env') &&
197
- !/express/i.test(message) &&
198
- !/local:/i.test(message) &&
199
- !/health check:/i.test(message) &&
200
- !/environment:/i.test(message)) {
201
- const prefix = this.options.verbose ?
202
- chalk_1.default.dim(`[Worker ${workerId}] `) : '';
203
- console.log(prefix + message);
204
- }
205
- });
206
- (_b = workerProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
207
- const message = data.toString().trim();
208
- if (message && !message.includes('[dotenv@') && !message.includes('injecting env')) {
209
- const prefix = this.options.verbose ?
210
- chalk_1.default.dim(`[Worker ${workerId}] `) : '';
211
- console.error(prefix + chalk_1.default.red(message));
212
- }
213
- });
214
- workerProcess.on('error', (error) => {
215
- this.log(`Worker ${workerId} error: ${error.message}`, 'error');
216
- });
217
- workerProcess.on('exit', (code, signal) => {
218
- this.workers.delete(workerId);
219
- if (!this.isShuttingDown && code !== 0 && signal !== 'SIGTERM') {
220
- this.log(`Worker ${workerId} crashed (code: ${code}, signal: ${signal})`, 'error');
221
- this.restartWorker(workerId);
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
- clearTimeout(timeout);
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
- clearTimeout(timeout);
237
- reject(error);
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
- clearTimeout(timeout);
241
- if (code !== 0) {
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
- resolve();
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.green(figures_1.default.tick)} Server partially ready on port ${this.options.port || 8000} (${this.workers.size} workers)`);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.6.65",
3
+ "version": "0.6.67",
4
4
  "description": "The Modern Build System for Polyrepo-in-Monorepo Architecture",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",