neex 0.6.55 → 0.6.60

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.
@@ -90,17 +90,29 @@ function addStartCommands(program) {
90
90
  const isDevelopment = options.watch || process.env.NODE_ENV === 'development';
91
91
  const isProduction = !isDevelopment;
92
92
  const cpuCount = os_1.default.cpus().length;
93
- // Smart worker allocation
93
+ // Smart worker allocation - more conservative approach
94
94
  let workers = options.workers;
95
95
  if (!workers) {
96
96
  if (isDevelopment) {
97
- workers = 1;
97
+ workers = 1; // Always single worker in development
98
98
  }
99
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
100
+ // For production, be more conservative
101
+ if (cpuCount <= 2) {
102
+ workers = 1; // Single worker for small systems
103
+ }
104
+ else if (cpuCount <= 4) {
105
+ workers = 2; // Two workers for medium systems
106
+ }
107
+ else {
108
+ workers = Math.min(Math.floor(cpuCount / 2), 4); // Max 4 workers
109
+ }
102
110
  }
103
111
  }
112
+ // Force single worker for development or debugging
113
+ if (isDevelopment || options.inspect || options.inspectBrk) {
114
+ workers = 1;
115
+ }
104
116
  const healthCheck = options.health !== false;
105
117
  const defaultPort = parseInt(process.env.PORT || '8000');
106
118
  const port = options.port || defaultPort;
@@ -118,22 +130,26 @@ function addStartCommands(program) {
118
130
  logger_manager_js_1.loggerManager.printLine(`Environment: ${process.env.NODE_ENV}`);
119
131
  logger_manager_js_1.loggerManager.printLine(`Port: ${port}`);
120
132
  logger_manager_js_1.loggerManager.printLine(`Workers: ${workers}`);
133
+ logger_manager_js_1.loggerManager.printLine(`CPU Cores: ${cpuCount}`);
121
134
  if (healthCheck) {
122
135
  logger_manager_js_1.loggerManager.printLine(`Health Check: http://localhost:${options.healthPort}/health`);
123
136
  }
124
137
  }
138
+ // Optimize memory settings based on workers
139
+ const memoryPerWorker = workers > 1 ? Math.floor(512 / workers) : 512;
140
+ const maxMemoryPerWorker = workers > 1 ? Math.floor(1024 / workers) : 1024;
125
141
  startManager = new start_manager_js_1.StartManager({
126
142
  file: resolvedFile,
127
143
  workingDir: options.dir,
128
144
  envFile: options.env,
129
145
  port,
130
146
  workers,
131
- memoryLimit: isProduction ? '512M' : undefined,
147
+ memoryLimit: isProduction ? `${memoryPerWorker}M` : undefined,
132
148
  logLevel: options.verbose ? 'debug' : 'info',
133
149
  color: process.stdout.isTTY,
134
150
  verbose: options.verbose,
135
151
  watch: options.watch,
136
- maxMemory: options.maxMemory || (isProduction ? '1G' : undefined),
152
+ maxMemory: options.maxMemory || (isProduction ? `${maxMemoryPerWorker}M` : undefined),
137
153
  maxCrashes: isProduction ? 3 : 10,
138
154
  restartDelay: isProduction ? 1000 : 500,
139
155
  healthCheck,
@@ -24,6 +24,7 @@ class StartManager {
24
24
  this.totalRestarts = 0;
25
25
  this.envLoaded = false;
26
26
  this.masterProcess = null;
27
+ this.readyWorkers = 0;
27
28
  this.options = options;
28
29
  this.startTime = new Date();
29
30
  this.debouncedRestart = (0, lodash_1.debounce)(this.restartAll.bind(this), options.restartDelay);
@@ -86,10 +87,10 @@ class StartManager {
86
87
  args.push(`--max-old-space-size=${memoryMB}`);
87
88
  }
88
89
  }
89
- if (this.options.inspect) {
90
+ if (this.options.inspect && this.options.workers === 1) {
90
91
  args.push('--inspect');
91
92
  }
92
- if (this.options.inspectBrk) {
93
+ if (this.options.inspectBrk && this.options.workers === 1) {
93
94
  args.push('--inspect-brk');
94
95
  }
95
96
  if (this.options.nodeArgs) {
@@ -98,6 +99,7 @@ class StartManager {
98
99
  return args;
99
100
  }
100
101
  async startSingleProcess() {
102
+ var _a, _b;
101
103
  const nodeArgs = this.getNodeArgs();
102
104
  const port = this.options.port || 8000;
103
105
  const env = {
@@ -105,13 +107,31 @@ class StartManager {
105
107
  NODE_ENV: process.env.NODE_ENV || 'production',
106
108
  PORT: port.toString(),
107
109
  FORCE_COLOR: this.options.color ? '1' : '0',
108
- NODE_OPTIONS: '--no-deprecation'
110
+ NODE_OPTIONS: '--no-deprecation',
111
+ CLUSTER_WORKER: 'false',
112
+ MASTER_PROCESS: 'true'
109
113
  };
114
+ if (this.options.verbose) {
115
+ this.log(`Starting single process on port ${port}`);
116
+ }
110
117
  this.masterProcess = (0, child_process_1.fork)(this.options.file, [], {
111
118
  cwd: this.options.workingDir,
112
119
  env,
113
120
  execArgv: nodeArgs,
114
- silent: false // Let the process handle its own output
121
+ silent: true
122
+ });
123
+ // Handle process output with filtering
124
+ (_a = this.masterProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
125
+ const message = data.toString().trim();
126
+ if (message && !this.shouldFilterMessage(message)) {
127
+ console.log(message);
128
+ }
129
+ });
130
+ (_b = this.masterProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
131
+ const message = data.toString().trim();
132
+ if (message && !this.shouldFilterMessage(message)) {
133
+ console.error(chalk_1.default.red(message));
134
+ }
115
135
  });
116
136
  this.masterProcess.on('error', (error) => {
117
137
  this.log(`Process error: ${error.message}`, 'error');
@@ -156,9 +176,21 @@ class StartManager {
156
176
  });
157
177
  });
158
178
  if (this.options.verbose) {
159
- this.log(`Process started (PID: ${this.masterProcess.pid}, Port: ${port})`);
179
+ this.log(`Process started (PID: ${this.masterProcess.pid})`);
160
180
  }
161
181
  }
182
+ shouldFilterMessage(message) {
183
+ const filters = [
184
+ '[dotenv@',
185
+ 'injecting env',
186
+ 'Express (',
187
+ 'Local: http://localhost:',
188
+ 'Health Check: http://localhost:',
189
+ 'Environment: production',
190
+ 'Environment: development'
191
+ ];
192
+ return filters.some(filter => message.includes(filter));
193
+ }
162
194
  async startWorker(workerId) {
163
195
  var _a, _b;
164
196
  const nodeArgs = this.getNodeArgs();
@@ -169,9 +201,14 @@ class StartManager {
169
201
  WORKER_ID: workerId.toString(),
170
202
  PORT: port.toString(),
171
203
  CLUSTER_WORKER: 'true',
204
+ MASTER_PROCESS: 'false',
172
205
  FORCE_COLOR: this.options.color ? '1' : '0',
173
- NODE_OPTIONS: '--no-deprecation'
206
+ NODE_OPTIONS: '--no-deprecation',
207
+ SUPPRESS_STARTUP_LOGS: 'true' // Signal to suppress duplicate logs
174
208
  };
209
+ if (this.options.verbose) {
210
+ this.log(`Starting worker ${workerId}`);
211
+ }
175
212
  const workerProcess = (0, child_process_1.fork)(this.options.file, [], {
176
213
  cwd: this.options.workingDir,
177
214
  env,
@@ -184,13 +221,14 @@ class StartManager {
184
221
  restarts: 0,
185
222
  startTime: new Date(),
186
223
  id: workerId,
187
- port: port
224
+ port: port,
225
+ ready: false
188
226
  };
189
227
  this.workers.set(workerId, workerInfo);
190
- // Handle worker output
228
+ // Handle worker output with filtering
191
229
  (_a = workerProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
192
230
  const message = data.toString().trim();
193
- if (message && !message.includes('[dotenv@') && !message.includes('injecting env')) {
231
+ if (message && !this.shouldFilterMessage(message)) {
194
232
  const prefix = this.options.verbose ?
195
233
  chalk_1.default.dim(`[Worker ${workerId}] `) : '';
196
234
  console.log(prefix + message);
@@ -198,7 +236,7 @@ class StartManager {
198
236
  });
199
237
  (_b = workerProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
200
238
  const message = data.toString().trim();
201
- if (message && !message.includes('[dotenv@') && !message.includes('injecting env')) {
239
+ if (message && !this.shouldFilterMessage(message)) {
202
240
  const prefix = this.options.verbose ?
203
241
  chalk_1.default.dim(`[Worker ${workerId}] `) : '';
204
242
  console.error(prefix + chalk_1.default.red(message));
@@ -217,11 +255,15 @@ class StartManager {
217
255
  // Wait for worker to be ready
218
256
  await new Promise((resolve, reject) => {
219
257
  const timeout = setTimeout(() => {
258
+ workerInfo.ready = true;
259
+ this.readyWorkers++;
220
260
  resolve(); // Don't reject, assume it's ready
221
261
  }, 5000);
222
262
  workerProcess.on('message', (message) => {
223
263
  if (message && message.type === 'ready') {
224
264
  clearTimeout(timeout);
265
+ workerInfo.ready = true;
266
+ this.readyWorkers++;
225
267
  resolve();
226
268
  }
227
269
  });
@@ -285,11 +327,11 @@ class StartManager {
285
327
  }
286
328
  async startCluster() {
287
329
  if (this.options.workers === 1) {
288
- // Single process mode
289
330
  await this.startSingleProcess();
290
331
  return;
291
332
  }
292
333
  // Multi-worker mode
334
+ this.readyWorkers = 0;
293
335
  const startPromises = [];
294
336
  for (let i = 0; i < this.options.workers; i++) {
295
337
  startPromises.push(this.startWorker(i + 1));
@@ -315,16 +357,23 @@ class StartManager {
315
357
  return;
316
358
  }
317
359
  if (req.url === '/health') {
360
+ const activeWorkers = this.options.workers === 1 ?
361
+ (this.masterProcess ? 1 : 0) :
362
+ this.workers.size;
318
363
  const stats = {
319
364
  status: 'ok',
320
365
  uptime: Date.now() - this.startTime.getTime(),
321
- workers: this.workers.size,
322
- activeWorkers: Array.from(this.workers.values()).map(w => ({
323
- id: w.id,
324
- pid: w.pid,
325
- restarts: w.restarts,
326
- uptime: Date.now() - w.startTime.getTime()
327
- })),
366
+ workers: activeWorkers,
367
+ expectedWorkers: this.options.workers,
368
+ activeWorkers: this.options.workers === 1 ?
369
+ (this.masterProcess ? [{ id: 1, pid: this.masterProcess.pid, uptime: Date.now() - this.startTime.getTime() }] : []) :
370
+ Array.from(this.workers.values()).map(w => ({
371
+ id: w.id,
372
+ pid: w.pid,
373
+ restarts: w.restarts,
374
+ uptime: Date.now() - w.startTime.getTime(),
375
+ ready: w.ready
376
+ })),
328
377
  totalRestarts: this.totalRestarts,
329
378
  memory: process.memoryUsage(),
330
379
  cpu: os_1.default.loadavg(),
@@ -379,7 +428,6 @@ class StartManager {
379
428
  return;
380
429
  this.log('Restarting due to file changes...');
381
430
  if (this.options.workers === 1 && this.masterProcess) {
382
- // Single process restart
383
431
  try {
384
432
  this.masterProcess.kill('SIGTERM');
385
433
  await this.waitForProcessExit(this.masterProcess, 5000);
@@ -392,7 +440,6 @@ class StartManager {
392
440
  }, this.options.restartDelay);
393
441
  }
394
442
  else {
395
- // Multi-worker restart
396
443
  const restartPromises = [];
397
444
  for (const [workerId, workerInfo] of this.workers.entries()) {
398
445
  restartPromises.push((async () => {
@@ -422,8 +469,9 @@ class StartManager {
422
469
  await this.startCluster();
423
470
  // Success message
424
471
  const port = this.options.port || 8000;
472
+ const actualWorkers = this.options.workers === 1 ? 1 : this.workers.size;
425
473
  const workerInfo = this.options.workers === 1 ?
426
- '' : ` (${this.workers.size} workers)`;
474
+ '' : ` (${actualWorkers} workers)`;
427
475
  logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} Server ready on port ${port}${workerInfo}`, 'info');
428
476
  }
429
477
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.6.55",
3
+ "version": "0.6.60",
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",