neex 0.6.51 → 0.6.52

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,40 +10,31 @@ 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"));
13
14
  function addStartCommands(program) {
14
15
  let startManager = null;
15
- // Start command for production execution
16
+ // Single optimized start command for production
16
17
  program
17
18
  .command('start [file]')
18
- .description('Start production application (default: dist/index.js)')
19
+ .description('Start production application with automatic optimization')
19
20
  .option('-d, --dir <directory>', 'Working directory', process.cwd())
20
21
  .option('-e, --env <file>', 'Environment file to load', '.env')
21
- .option('-p, --port <port>', 'Port number (if applicable)', parseInt)
22
- .option('-w, --workers <count>', 'Number of worker processes', parseInt, 1)
23
- .option('-c, --cluster', 'Enable cluster mode')
24
- .option('-m, --memory <limit>', 'Memory limit (e.g., 512M, 1G)')
25
- .option('-l, --log-level <level>', 'Log level (error, warn, info, debug)', 'info')
26
- .option('-f, --log-file <file>', 'Log file path')
27
- .option('--no-color', 'Disable colored output')
28
- .option('-q, --quiet', 'Quiet mode')
22
+ .option('-p, --port <port>', 'Port number', parseInt)
23
+ .option('-w, --workers <count>', 'Number of worker processes (default: auto)', parseInt)
29
24
  .option('-v, --verbose', 'Verbose output')
30
- .option('--watch', 'Watch for changes and restart')
31
- .option('--max-memory <limit>', 'Maximum memory before restart (e.g., 1G)')
32
- .option('--max-crashes <count>', 'Maximum crashes before giving up', parseInt, 5)
33
- .option('--restart-delay <ms>', 'Delay between restarts (ms)', parseInt, 1000)
34
- .option('--health-check', 'Enable health check monitoring')
25
+ .option('--watch', 'Watch for changes and restart (development mode)')
26
+ .option('--no-health', 'Disable health check endpoint')
35
27
  .option('--health-port <port>', 'Health check port', parseInt, 3001)
28
+ .option('--max-memory <limit>', 'Maximum memory before restart (e.g., 1G)')
36
29
  .option('--graceful-timeout <ms>', 'Graceful shutdown timeout (ms)', parseInt, 30000)
37
30
  .option('--inspect', 'Enable Node.js inspector')
38
31
  .option('--inspect-brk', 'Enable Node.js inspector with break')
39
- .option('--node-args <args>', 'Additional Node.js arguments')
40
32
  .action(async (file, options) => {
41
33
  try {
42
34
  const targetFile = file || 'dist/index.js';
43
35
  const resolvedFile = path_1.default.resolve(options.dir, targetFile);
44
- // Check if file exists
36
+ // Auto-detect main file if not found
45
37
  if (!fs_1.default.existsSync(resolvedFile)) {
46
- // Try to find main file from package.json
47
38
  const packageJsonPath = path_1.default.join(options.dir, 'package.json');
48
39
  if (fs_1.default.existsSync(packageJsonPath)) {
49
40
  const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'));
@@ -51,155 +42,56 @@ function addStartCommands(program) {
51
42
  const alternativeFile = path_1.default.resolve(options.dir, mainFile);
52
43
  if (fs_1.default.existsSync(alternativeFile)) {
53
44
  if (options.verbose) {
54
- logger_manager_js_1.loggerManager.printLine(`Using main file from package.json: ${mainFile}`, 'info');
45
+ logger_manager_js_1.loggerManager.printLine(`Using main file: ${mainFile}`, 'info');
55
46
  }
56
47
  }
57
48
  else {
58
- throw new Error(`Neither ${targetFile} nor ${mainFile} found. Please build your project first.`);
49
+ throw new Error(`Application file not found. Please build your project first.`);
59
50
  }
60
51
  }
61
52
  else {
62
- throw new Error(`File not found: ${resolvedFile}. Please build your project first.`);
53
+ throw new Error(`Application file not found: ${resolvedFile}`);
63
54
  }
64
55
  }
65
- if (!options.quiet) {
66
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting production server: ${chalk_1.default.cyan(targetFile)}`, 'info');
67
- }
56
+ // Auto-detect optimal configuration
57
+ const isDevelopment = options.watch || process.env.NODE_ENV === 'development';
58
+ const isProduction = !isDevelopment;
59
+ const cpuCount = os_1.default.cpus().length;
60
+ const workers = options.workers || (isProduction ? cpuCount : 1);
61
+ const healthCheck = options.health !== false && isProduction;
62
+ // Startup logging
63
+ const mode = isDevelopment ? 'development' : 'production';
64
+ const clusterInfo = workers > 1 ? ` (${workers} workers)` : '';
65
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.play)} Starting ${mode} server${clusterInfo}`, 'info');
68
66
  startManager = new start_manager_js_1.StartManager({
69
67
  file: resolvedFile,
70
68
  workingDir: options.dir,
71
69
  envFile: options.env,
72
70
  port: options.port,
73
- workers: options.workers,
74
- cluster: options.cluster,
75
- memoryLimit: options.memory,
76
- logLevel: options.logLevel,
77
- logFile: options.logFile,
78
- color: options.color,
79
- quiet: options.quiet,
71
+ workers,
72
+ memoryLimit: isProduction ? '512M' : undefined,
73
+ logLevel: options.verbose ? 'debug' : 'info',
74
+ color: true,
80
75
  verbose: options.verbose,
81
76
  watch: options.watch,
82
- maxMemory: options.maxMemory,
83
- maxCrashes: options.maxCrashes,
84
- restartDelay: options.restartDelay,
85
- healthCheck: options.healthCheck,
77
+ maxMemory: options.maxMemory || (isProduction ? '1G' : undefined),
78
+ maxCrashes: isProduction ? 3 : 5,
79
+ restartDelay: isProduction ? 2000 : 1000,
80
+ healthCheck,
86
81
  healthPort: options.healthPort,
87
82
  gracefulTimeout: options.gracefulTimeout,
88
83
  inspect: options.inspect,
89
84
  inspectBrk: options.inspectBrk,
90
- nodeArgs: options.nodeArgs
91
- });
92
- await startManager.start();
93
- }
94
- catch (error) {
95
- if (error instanceof Error) {
96
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Start failed: ${error.message}`, 'error');
97
- }
98
- else {
99
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown start error occurred`, 'error');
100
- }
101
- process.exit(1);
102
- }
103
- });
104
- // Quick start command
105
- program
106
- .command('run [file]')
107
- .description('Quick start without options (alias for start)')
108
- .action(async (file) => {
109
- try {
110
- const targetFile = file || 'dist/index.js';
111
- if (!fs_1.default.existsSync(targetFile)) {
112
- throw new Error(`File not found: ${targetFile}. Please build your project first.`);
113
- }
114
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Running: ${chalk_1.default.cyan(targetFile)}`, 'info');
115
- startManager = new start_manager_js_1.StartManager({
116
- file: path_1.default.resolve(targetFile),
117
- workingDir: process.cwd(),
118
- envFile: '.env',
119
- port: undefined,
120
- workers: 1,
121
- cluster: false,
122
- memoryLimit: undefined,
123
- logLevel: 'info',
124
- logFile: undefined,
125
- color: true,
126
- quiet: false,
127
- verbose: false,
128
- watch: false,
129
- maxMemory: undefined,
130
- maxCrashes: 5,
131
- restartDelay: 1000,
132
- healthCheck: false,
133
- healthPort: 3001,
134
- gracefulTimeout: 30000,
135
- inspect: false,
136
- inspectBrk: false,
137
85
  nodeArgs: undefined
138
86
  });
139
87
  await startManager.start();
140
88
  }
141
89
  catch (error) {
142
90
  if (error instanceof Error) {
143
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Run failed: ${error.message}`, 'error');
91
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} ${error.message}`, 'error');
144
92
  }
145
93
  else {
146
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown run error occurred`, 'error');
147
- }
148
- process.exit(1);
149
- }
150
- });
151
- // Production command with clustering
152
- program
153
- .command('prod [file]')
154
- .description('Start in production mode with clustering')
155
- .option('-w, --workers <count>', 'Number of workers (default: CPU cores)', parseInt)
156
- .option('-p, --port <port>', 'Port number', parseInt)
157
- .option('-e, --env <file>', 'Environment file', '.env.production')
158
- .option('-l, --log-file <file>', 'Log file path')
159
- .option('-q, --quiet', 'Quiet mode')
160
- .action(async (file, options) => {
161
- try {
162
- const targetFile = file || 'dist/index.js';
163
- const resolvedFile = path_1.default.resolve(targetFile);
164
- if (!fs_1.default.existsSync(resolvedFile)) {
165
- throw new Error(`File not found: ${resolvedFile}. Please build your project first.`);
166
- }
167
- const workers = options.workers || require('os').cpus().length;
168
- if (!options.quiet) {
169
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting production server with ${workers} workers`, 'info');
170
- }
171
- startManager = new start_manager_js_1.StartManager({
172
- file: resolvedFile,
173
- workingDir: process.cwd(),
174
- envFile: options.env,
175
- port: options.port,
176
- workers,
177
- cluster: true,
178
- memoryLimit: undefined,
179
- logLevel: 'info',
180
- logFile: options.logFile,
181
- color: false,
182
- quiet: options.quiet,
183
- verbose: false,
184
- watch: false,
185
- maxMemory: '1G',
186
- maxCrashes: 3,
187
- restartDelay: 2000,
188
- healthCheck: true,
189
- healthPort: 3001,
190
- gracefulTimeout: 30000,
191
- inspect: false,
192
- inspectBrk: false,
193
- nodeArgs: undefined
194
- });
195
- await startManager.start();
196
- }
197
- catch (error) {
198
- if (error instanceof Error) {
199
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Production start failed: ${error.message}`, 'error');
200
- }
201
- else {
202
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown production start error occurred`, 'error');
94
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Startup failed`, 'error');
203
95
  }
204
96
  process.exit(1);
205
97
  }
@@ -219,7 +111,6 @@ function addStartCommands(program) {
219
111
  // Handle process termination
220
112
  const handleExit = (signal) => {
221
113
  if (startManager) {
222
- logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received ${signal}, stopping server...`, 'info');
223
114
  cleanupStart().then(() => {
224
115
  process.exit(0);
225
116
  }).catch(() => {
@@ -233,12 +124,7 @@ function addStartCommands(program) {
233
124
  // Register signal handlers
234
125
  process.on('SIGINT', () => handleExit('SIGINT'));
235
126
  process.on('SIGTERM', () => handleExit('SIGTERM'));
236
- process.on('SIGUSR2', () => handleExit('SIGUSR2')); // PM2 restart
237
- process.on('exit', () => {
238
- if (startManager) {
239
- cleanupStart();
240
- }
241
- });
127
+ process.on('SIGUSR2', () => handleExit('SIGUSR2'));
242
128
  return { cleanupStart };
243
129
  }
244
130
  exports.addStartCommands = addStartCommands;
@@ -4,11 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.StartManager = void 0;
7
- // src/start-manager.ts - Production start manager with clustering and monitoring
7
+ // src/start-manager.ts - Optimized production start manager
8
8
  const child_process_1 = require("child_process");
9
9
  const chokidar_1 = require("chokidar");
10
10
  const logger_manager_js_1 = require("./logger-manager.js");
11
11
  const chalk_1 = __importDefault(require("chalk"));
12
+ const figures_1 = __importDefault(require("figures"));
12
13
  const path_1 = __importDefault(require("path"));
13
14
  const fs_1 = __importDefault(require("fs"));
14
15
  const http_1 = __importDefault(require("http"));
@@ -16,43 +17,16 @@ const lodash_1 = require("lodash");
16
17
  class StartManager {
17
18
  constructor(options) {
18
19
  this.workers = new Map();
19
- this.masterProcess = null;
20
20
  this.watcher = null;
21
21
  this.healthServer = null;
22
22
  this.isShuttingDown = false;
23
- this.logStream = null;
24
23
  this.totalRestarts = 0;
25
24
  this.options = options;
26
25
  this.startTime = new Date();
27
26
  this.debouncedRestart = (0, lodash_1.debounce)(this.restartAll.bind(this), options.restartDelay);
28
- this.setupLogging();
29
- }
30
- setupLogging() {
31
- if (this.options.logFile) {
32
- try {
33
- const logDir = path_1.default.dirname(this.options.logFile);
34
- if (!fs_1.default.existsSync(logDir)) {
35
- fs_1.default.mkdirSync(logDir, { recursive: true });
36
- }
37
- this.logStream = fs_1.default.createWriteStream(this.options.logFile, { flags: 'a' });
38
- if (this.options.verbose) {
39
- logger_manager_js_1.loggerManager.printLine(`Logging to: ${this.options.logFile}`, 'info');
40
- }
41
- }
42
- catch (error) {
43
- logger_manager_js_1.loggerManager.printLine(`Failed to setup logging: ${error.message}`, 'warn');
44
- }
45
- }
46
27
  }
47
28
  log(message, level = 'info') {
48
- const timestamp = new Date().toISOString();
49
- const logMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
50
- if (this.logStream) {
51
- this.logStream.write(logMessage + '\n');
52
- }
53
- if (!this.options.quiet) {
54
- logger_manager_js_1.loggerManager.printLine(message, level);
55
- }
29
+ logger_manager_js_1.loggerManager.printLine(message, level);
56
30
  }
57
31
  loadEnvFile() {
58
32
  if (this.options.envFile && fs_1.default.existsSync(this.options.envFile)) {
@@ -65,18 +39,16 @@ class StartManager {
65
39
  const [key, ...values] = trimmed.split('=');
66
40
  if (key && values.length > 0) {
67
41
  const value = values.join('=').trim();
68
- // Remove quotes if present
69
42
  const cleanValue = value.replace(/^["']|["']$/g, '');
70
43
  process.env[key.trim()] = cleanValue;
71
44
  }
72
45
  }
73
46
  }
74
- if (this.options.verbose) {
75
- this.log(`Loaded environment variables from ${this.options.envFile}`);
76
- }
77
47
  }
78
48
  catch (error) {
79
- this.log(`Failed to load environment file: ${error.message}`, 'warn');
49
+ if (this.options.verbose) {
50
+ this.log(`Failed to load environment file: ${error.message}`, 'warn');
51
+ }
80
52
  }
81
53
  }
82
54
  }
@@ -95,7 +67,8 @@ class StartManager {
95
67
  getNodeArgs() {
96
68
  const args = [];
97
69
  if (this.options.memoryLimit) {
98
- args.push(`--max-old-space-size=${this.parseMemoryLimit(this.options.memoryLimit) / (1024 * 1024)}`);
70
+ const memoryMB = this.parseMemoryLimit(this.options.memoryLimit) / (1024 * 1024);
71
+ args.push(`--max-old-space-size=${memoryMB}`);
99
72
  }
100
73
  if (this.options.inspect) {
101
74
  args.push('--inspect');
@@ -125,32 +98,30 @@ class StartManager {
125
98
  cwd: this.options.workingDir,
126
99
  env,
127
100
  execArgv: nodeArgs,
128
- silent: true
101
+ silent: false
129
102
  });
130
103
  const workerInfo = {
131
104
  process: workerProcess,
132
105
  pid: workerProcess.pid,
133
106
  restarts: 0,
134
- startTime: new Date(),
135
- memoryUsage: 0,
136
- cpuUsage: 0
107
+ startTime: new Date()
137
108
  };
138
109
  this.workers.set(workerId, workerInfo);
139
110
  // Handle worker output
140
111
  (_a = workerProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
141
- if (!this.options.quiet) {
142
- const message = data.toString().trim();
143
- if (message) {
144
- console.log(chalk_1.default.dim(`[Worker ${workerId}]`) + ' ' + message);
145
- }
112
+ const message = data.toString().trim();
113
+ if (message) {
114
+ console.log(this.options.verbose ?
115
+ chalk_1.default.dim(`[Worker ${workerId}]`) + ' ' + message :
116
+ message);
146
117
  }
147
118
  });
148
119
  (_b = workerProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
149
- if (!this.options.quiet) {
150
- const message = data.toString().trim();
151
- if (message) {
152
- console.error(chalk_1.default.dim(`[Worker ${workerId}]`) + ' ' + chalk_1.default.red(message));
153
- }
120
+ const message = data.toString().trim();
121
+ if (message) {
122
+ console.error(this.options.verbose ?
123
+ chalk_1.default.dim(`[Worker ${workerId}]`) + ' ' + chalk_1.default.red(message) :
124
+ chalk_1.default.red(message));
154
125
  }
155
126
  });
156
127
  workerProcess.on('error', (error) => {
@@ -160,20 +131,14 @@ class StartManager {
160
131
  this.workers.delete(workerId);
161
132
  if (!this.isShuttingDown) {
162
133
  if (code !== 0) {
163
- this.log(`Worker ${workerId} exited with code ${code}`, 'error');
134
+ this.log(`Worker ${workerId} crashed (code: ${code})`, 'error');
164
135
  this.restartWorker(workerId);
165
136
  }
166
- else {
167
- this.log(`Worker ${workerId} exited gracefully`);
168
- }
169
137
  }
170
138
  });
171
- workerProcess.on('message', (message) => {
172
- if (this.options.verbose) {
173
- this.log(`Worker ${workerId} message: ${JSON.stringify(message)}`);
174
- }
175
- });
176
- this.log(`Started worker ${workerId} (PID: ${workerProcess.pid})`);
139
+ if (this.options.verbose) {
140
+ this.log(`Worker ${workerId} started (PID: ${workerProcess.pid})`);
141
+ }
177
142
  return workerInfo;
178
143
  }
179
144
  async restartWorker(workerId) {
@@ -182,11 +147,12 @@ class StartManager {
182
147
  workerInfo.restarts++;
183
148
  this.totalRestarts++;
184
149
  if (workerInfo.restarts >= this.options.maxCrashes) {
185
- this.log(`Worker ${workerId} reached max crashes (${this.options.maxCrashes}), not restarting`, 'error');
150
+ this.log(`Worker ${workerId} reached max crashes, not restarting`, 'error');
186
151
  return;
187
152
  }
188
- this.log(`Restarting worker ${workerId} (restart #${workerInfo.restarts})`);
189
- // Graceful shutdown
153
+ if (this.options.verbose) {
154
+ this.log(`Restarting worker ${workerId} (attempt ${workerInfo.restarts})`);
155
+ }
190
156
  try {
191
157
  workerInfo.process.kill('SIGTERM');
192
158
  await this.waitForProcessExit(workerInfo.process, 5000);
@@ -194,7 +160,6 @@ class StartManager {
194
160
  catch (error) {
195
161
  workerInfo.process.kill('SIGKILL');
196
162
  }
197
- // Start new worker
198
163
  setTimeout(() => {
199
164
  this.startWorker(workerId);
200
165
  }, this.options.restartDelay);
@@ -211,49 +176,7 @@ class StartManager {
211
176
  });
212
177
  });
213
178
  }
214
- async startSingleProcess() {
215
- const nodeArgs = this.getNodeArgs();
216
- const env = {
217
- ...process.env,
218
- NODE_ENV: process.env.NODE_ENV || 'production',
219
- FORCE_COLOR: this.options.color ? '1' : '0'
220
- };
221
- if (this.options.port) {
222
- env.PORT = this.options.port.toString();
223
- }
224
- this.masterProcess = (0, child_process_1.spawn)('node', [...nodeArgs, this.options.file], {
225
- cwd: this.options.workingDir,
226
- env,
227
- stdio: this.options.quiet ? 'ignore' : 'inherit'
228
- });
229
- this.masterProcess.on('error', (error) => {
230
- this.log(`Process error: ${error.message}`, 'error');
231
- });
232
- this.masterProcess.on('exit', (code, signal) => {
233
- if (!this.isShuttingDown) {
234
- if (code !== 0) {
235
- this.log(`Process exited with code ${code}`, 'error');
236
- if (this.totalRestarts < this.options.maxCrashes) {
237
- this.totalRestarts++;
238
- this.log(`Restarting process (restart #${this.totalRestarts})`);
239
- setTimeout(() => {
240
- this.startSingleProcess();
241
- }, this.options.restartDelay);
242
- }
243
- else {
244
- this.log(`Reached max crashes (${this.options.maxCrashes}), giving up`, 'error');
245
- process.exit(1);
246
- }
247
- }
248
- else {
249
- this.log('Process exited gracefully');
250
- }
251
- }
252
- });
253
- this.log(`Started process (PID: ${this.masterProcess.pid})`);
254
- }
255
179
  async startCluster() {
256
- this.log(`Starting cluster with ${this.options.workers} workers`);
257
180
  for (let i = 0; i < this.options.workers; i++) {
258
181
  await this.startWorker(i + 1);
259
182
  }
@@ -268,11 +191,10 @@ class StartManager {
268
191
  uptime: Date.now() - this.startTime.getTime(),
269
192
  workers: this.workers.size,
270
193
  totalRestarts: this.totalRestarts,
271
- memoryUsage: process.memoryUsage(),
272
- cpuUsage: process.cpuUsage()
194
+ memory: process.memoryUsage()
273
195
  };
274
196
  res.writeHead(200, { 'Content-Type': 'application/json' });
275
- res.end(JSON.stringify(stats, null, 2));
197
+ res.end(JSON.stringify(stats));
276
198
  }
277
199
  else {
278
200
  res.writeHead(404);
@@ -280,7 +202,9 @@ class StartManager {
280
202
  }
281
203
  });
282
204
  this.healthServer.listen(this.options.healthPort, () => {
283
- this.log(`Health check server listening on port ${this.options.healthPort}`);
205
+ if (this.options.verbose) {
206
+ this.log(`Health endpoint: http://localhost:${this.options.healthPort}/health`);
207
+ }
284
208
  });
285
209
  }
286
210
  setupWatcher() {
@@ -292,15 +216,8 @@ class StartManager {
292
216
  `${this.options.workingDir}/**/*.env*`
293
217
  ];
294
218
  this.watcher = (0, chokidar_1.watch)(watchPatterns, {
295
- ignored: [
296
- '**/node_modules/**',
297
- '**/.git/**',
298
- '**/logs/**',
299
- '**/*.log'
300
- ],
219
+ ignored: ['**/node_modules/**', '**/.git/**', '**/logs/**'],
301
220
  ignoreInitial: true,
302
- followSymlinks: false,
303
- usePolling: false,
304
221
  atomic: 300
305
222
  });
306
223
  this.watcher.on('change', (filePath) => {
@@ -309,94 +226,61 @@ class StartManager {
309
226
  }
310
227
  this.debouncedRestart();
311
228
  });
312
- this.watcher.on('error', (error) => {
313
- this.log(`Watcher error: ${error.message}`, 'error');
314
- });
315
- this.log('File watcher enabled');
229
+ if (this.options.verbose) {
230
+ this.log('File watching enabled');
231
+ }
316
232
  }
317
233
  async restartAll() {
318
234
  if (this.isShuttingDown)
319
235
  return;
320
- this.log('Restarting all processes due to file changes');
321
- if (this.options.cluster) {
322
- // Graceful restart of workers
323
- for (const [workerId, workerInfo] of this.workers.entries()) {
324
- try {
325
- workerInfo.process.kill('SIGTERM');
326
- await this.waitForProcessExit(workerInfo.process, 5000);
327
- }
328
- catch (error) {
329
- workerInfo.process.kill('SIGKILL');
330
- }
331
- // Start new worker
332
- setTimeout(() => {
333
- this.startWorker(workerId);
334
- }, this.options.restartDelay);
335
- }
336
- }
337
- else if (this.masterProcess) {
338
- // Restart single process
236
+ this.log('Restarting due to file changes...');
237
+ for (const [workerId, workerInfo] of this.workers.entries()) {
339
238
  try {
340
- this.masterProcess.kill('SIGTERM');
341
- await this.waitForProcessExit(this.masterProcess, 5000);
239
+ workerInfo.process.kill('SIGTERM');
240
+ await this.waitForProcessExit(workerInfo.process, 5000);
342
241
  }
343
242
  catch (error) {
344
- this.masterProcess.kill('SIGKILL');
243
+ workerInfo.process.kill('SIGKILL');
345
244
  }
346
245
  setTimeout(() => {
347
- this.startSingleProcess();
246
+ this.startWorker(workerId);
348
247
  }, this.options.restartDelay);
349
248
  }
350
249
  }
351
- setupMonitoring() {
250
+ setupMemoryMonitoring() {
251
+ if (!this.options.maxMemory)
252
+ return;
253
+ const maxMemory = this.parseMemoryLimit(this.options.maxMemory);
254
+ if (!maxMemory)
255
+ return;
352
256
  setInterval(() => {
353
- if (this.options.verbose) {
354
- this.workers.forEach((workerInfo, workerId) => {
355
- try {
356
- const usage = process.memoryUsage();
357
- workerInfo.memoryUsage = usage.heapUsed;
358
- if (this.options.maxMemory) {
359
- const maxMemory = this.parseMemoryLimit(this.options.maxMemory);
360
- if (maxMemory && usage.heapUsed > maxMemory) {
361
- this.log(`Worker ${workerId} exceeded memory limit, restarting`, 'warn');
362
- this.restartWorker(workerId);
363
- }
364
- }
365
- }
366
- catch (error) {
367
- // Ignore monitoring errors
257
+ this.workers.forEach((workerInfo, workerId) => {
258
+ try {
259
+ const usage = process.memoryUsage();
260
+ if (usage.heapUsed > maxMemory) {
261
+ this.log(`Worker ${workerId} exceeded memory limit, restarting`, 'warn');
262
+ this.restartWorker(workerId);
368
263
  }
369
- });
370
- }
371
- }, 10000); // Check every 10 seconds
264
+ }
265
+ catch (error) {
266
+ // Ignore monitoring errors
267
+ }
268
+ });
269
+ }, 30000); // Check every 30 seconds
372
270
  }
373
271
  async start() {
374
272
  try {
375
273
  this.loadEnvFile();
376
274
  this.setupHealthCheck();
377
275
  this.setupWatcher();
378
- this.setupMonitoring();
379
- const runtime = Date.now() - this.startTime.getTime();
380
- this.log(`Starting application in ${runtime}ms`);
381
- if (this.options.cluster) {
382
- await this.startCluster();
383
- }
384
- else {
385
- await this.startSingleProcess();
386
- }
387
- this.log(`Application started successfully`);
388
- if (this.options.verbose) {
389
- this.log(`Configuration: ${JSON.stringify({
390
- workers: this.options.workers,
391
- cluster: this.options.cluster,
392
- watch: this.options.watch,
393
- healthCheck: this.options.healthCheck,
394
- port: this.options.port
395
- })}`);
396
- }
276
+ this.setupMemoryMonitoring();
277
+ await this.startCluster();
278
+ // Success message
279
+ const port = this.options.port || process.env.PORT;
280
+ const portInfo = port ? ` on port ${port}` : '';
281
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} Server ready${portInfo}`, 'info');
397
282
  }
398
283
  catch (error) {
399
- this.log(`Failed to start application: ${error.message}`, 'error');
400
284
  throw error;
401
285
  }
402
286
  }
@@ -404,18 +288,12 @@ class StartManager {
404
288
  if (this.isShuttingDown)
405
289
  return;
406
290
  this.isShuttingDown = true;
407
- this.log('Stopping application...');
408
- // Stop watcher
409
291
  if (this.watcher) {
410
292
  await this.watcher.close();
411
- this.watcher = null;
412
293
  }
413
- // Stop health server
414
294
  if (this.healthServer) {
415
295
  this.healthServer.close();
416
- this.healthServer = null;
417
296
  }
418
- // Stop all workers
419
297
  const shutdownPromises = [];
420
298
  for (const [workerId, workerInfo] of this.workers.entries()) {
421
299
  shutdownPromises.push((async () => {
@@ -428,29 +306,8 @@ class StartManager {
428
306
  }
429
307
  })());
430
308
  }
431
- // Stop master process
432
- if (this.masterProcess) {
433
- shutdownPromises.push((async () => {
434
- try {
435
- this.masterProcess.kill('SIGTERM');
436
- await this.waitForProcessExit(this.masterProcess, this.options.gracefulTimeout);
437
- }
438
- catch (error) {
439
- this.masterProcess.kill('SIGKILL');
440
- }
441
- })());
442
- }
443
- // Wait for all processes to shut down
444
309
  await Promise.allSettled(shutdownPromises);
445
- // Close log stream
446
- if (this.logStream) {
447
- this.logStream.end();
448
- this.logStream = null;
449
- }
450
- const uptime = Date.now() - this.startTime.getTime();
451
- this.log(`Application stopped after ${uptime}ms uptime`);
452
310
  this.workers.clear();
453
- this.masterProcess = null;
454
311
  }
455
312
  }
456
313
  exports.StartManager = StartManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.6.51",
3
+ "version": "0.6.52",
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",