neex 0.6.20 → 0.6.22
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/README.md +1 -1
- package/dist/src/commands/build-commands.js +46 -36
- package/dist/src/commands/start-commands.js +59 -57
- package/dist/src/start-manager.js +121 -34
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,7 +110,7 @@ function addBuildCommands(program) {
|
|
|
110
110
|
.option('-d, --delay <ms>', 'Delay before rebuild in milliseconds', parseInt)
|
|
111
111
|
.option('--clean', 'Clean output directory before build')
|
|
112
112
|
.option('--verbose', 'Verbose output')
|
|
113
|
-
.option('--info', 'Show detailed information
|
|
113
|
+
.option('--info', 'Show detailed build information')
|
|
114
114
|
.option('--source-map', 'Generate source maps')
|
|
115
115
|
.option('--target <target>', 'Target ECMAScript version', 'es2020')
|
|
116
116
|
.option('--module <module>', 'Module system', 'commonjs')
|
|
@@ -129,14 +129,32 @@ function addBuildCommands(program) {
|
|
|
129
129
|
process.exit(1);
|
|
130
130
|
}
|
|
131
131
|
// Get build configuration
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
132
|
+
const buildConfig = await getBuildConfig(file, options.output, showInfo);
|
|
133
|
+
// Create BuildManager instance with all required options
|
|
134
|
+
const buildManager = new build_manager_js_1.BuildManager({
|
|
135
|
+
runnerName: 'neex build',
|
|
136
|
+
inputFile: file,
|
|
137
|
+
outputDir: options.output,
|
|
138
|
+
buildType: buildConfig.buildType,
|
|
139
|
+
buildCommand: buildConfig.buildCommand,
|
|
140
|
+
showInfo: showInfo,
|
|
141
|
+
color: !options.color,
|
|
142
|
+
showTiming: !options.timing,
|
|
143
|
+
watch: options.watch,
|
|
144
|
+
delay: parseInt(options.delay),
|
|
145
|
+
verbose: options.verbose,
|
|
146
|
+
clean: options.clean,
|
|
147
|
+
sourceMap: options.sourceMap,
|
|
148
|
+
target: options.target,
|
|
149
|
+
module: options.module,
|
|
150
|
+
parallel: false,
|
|
151
|
+
groupOutput: false,
|
|
152
|
+
isServerMode: false,
|
|
153
|
+
printOutput: true,
|
|
154
|
+
prefix: true,
|
|
155
|
+
stopOnError: false,
|
|
156
|
+
minimalOutput: false
|
|
157
|
+
});
|
|
140
158
|
// Setup ignore patterns for watch mode
|
|
141
159
|
const ignorePatterns = options.ignore || [
|
|
142
160
|
'node_modules/**',
|
|
@@ -168,34 +186,26 @@ function addBuildCommands(program) {
|
|
|
168
186
|
console.log(chalk_1.default.green(`${figures_1.default.tick} neex build: Starting build process...`));
|
|
169
187
|
console.log(chalk_1.default.gray(`${'='.repeat(60)}`));
|
|
170
188
|
}
|
|
171
|
-
// Create BuildManager instance
|
|
172
|
-
buildManager = new build_manager_js_1.BuildManager({
|
|
173
|
-
runnerName: 'neex build',
|
|
174
|
-
inputFile: file,
|
|
175
|
-
outputDir: options.output,
|
|
176
|
-
buildType: buildConfig.buildType,
|
|
177
|
-
buildCommand: buildConfig.buildCommand,
|
|
178
|
-
color: options.color,
|
|
179
|
-
showTiming: options.timing,
|
|
180
|
-
prefix: options.prefix,
|
|
181
|
-
stopOnError: options.stopOnError,
|
|
182
|
-
printOutput: true,
|
|
183
|
-
minimalOutput: options.minimal,
|
|
184
|
-
watch: options.watch,
|
|
185
|
-
ignore: ignorePatterns,
|
|
186
|
-
delay: options.delay || 1000,
|
|
187
|
-
verbose: options.verbose,
|
|
188
|
-
showInfo: showInfo,
|
|
189
|
-
clean: options.clean,
|
|
190
|
-
sourceMap: options.sourceMap,
|
|
191
|
-
target: options.target,
|
|
192
|
-
module: options.module,
|
|
193
|
-
parallel: false,
|
|
194
|
-
groupOutput: false,
|
|
195
|
-
isServerMode: false
|
|
196
|
-
});
|
|
197
189
|
// Start the build process
|
|
198
|
-
|
|
190
|
+
try {
|
|
191
|
+
if (showInfo) {
|
|
192
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} neex build: Analyzing ${chalk_1.default.cyan(path.basename(file))}`));
|
|
193
|
+
}
|
|
194
|
+
await buildManager.start();
|
|
195
|
+
if (showInfo) {
|
|
196
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} Build completed successfully`));
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} Build completed`));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Build failed`));
|
|
204
|
+
if (error instanceof Error) {
|
|
205
|
+
console.error(chalk_1.default.red(`Error: ${error.message}`));
|
|
206
|
+
}
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
199
209
|
}
|
|
200
210
|
catch (error) {
|
|
201
211
|
console.error(chalk_1.default.red(`${figures_1.default.cross} neex build: Fatal error occurred`));
|
|
@@ -27,6 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.addStartCommands = void 0;
|
|
30
|
+
const start_manager_js_1 = require("../start-manager.js");
|
|
30
31
|
const chalk_1 = __importDefault(require("chalk"));
|
|
31
32
|
const figures_1 = __importDefault(require("figures"));
|
|
32
33
|
const path = __importStar(require("path"));
|
|
@@ -99,74 +100,75 @@ function addStartCommands(program) {
|
|
|
99
100
|
program
|
|
100
101
|
.command('start <file>')
|
|
101
102
|
.alias('s')
|
|
102
|
-
.description('Start
|
|
103
|
+
.description('Start a production application')
|
|
103
104
|
.option('-c, --no-color', 'Disable colored output')
|
|
104
105
|
.option('-t, --no-timing', 'Hide timing information')
|
|
105
|
-
.option('-
|
|
106
|
-
.option('-
|
|
107
|
-
.option('
|
|
108
|
-
.option('
|
|
109
|
-
.option('
|
|
110
|
-
.option('
|
|
111
|
-
.option('
|
|
112
|
-
.option('--
|
|
113
|
-
.option('--
|
|
114
|
-
.option('--verbose', 'Verbose output')
|
|
115
|
-
.option('--info', 'Show detailed information during startup')
|
|
116
|
-
.option('--signal <signal>', 'Signal to send to processes on restart', 'SIGTERM')
|
|
117
|
-
.option('--env <env>', 'Environment mode', 'production')
|
|
118
|
-
.option('--cluster', 'Enable cluster mode (spawn multiple processes)')
|
|
119
|
-
.option('--cluster-instances <number>', 'Number of cluster instances', parseInt)
|
|
120
|
-
.option('--memory-limit <mb>', 'Memory limit in MB', parseInt)
|
|
121
|
-
.option('--cpu-limit <percent>', 'CPU limit percentage', parseInt)
|
|
106
|
+
.option('-v, --verbose', 'Show detailed logs')
|
|
107
|
+
.option('-w, --watch', 'Watch for file changes')
|
|
108
|
+
.option('--delay <ms>', 'Delay between file changes (ms)', '1000')
|
|
109
|
+
.option('--environment <env>', 'Application environment', 'production')
|
|
110
|
+
.option('--cluster', 'Enable cluster mode')
|
|
111
|
+
.option('--instances <num>', 'Number of cluster instances', '1')
|
|
112
|
+
.option('--memory <mb>', 'Memory limit (MB)', '0')
|
|
113
|
+
.option('--cpu <percent>', 'CPU limit (%)', '0')
|
|
114
|
+
.option('--info', 'Show detailed start information')
|
|
122
115
|
.action(async (file, options) => {
|
|
123
116
|
try {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
117
|
+
// Get start command configuration
|
|
118
|
+
const startConfig = await getStartCommand(file, options.info);
|
|
119
|
+
// Create StartManager instance
|
|
120
|
+
const startManager = new start_manager_js_1.StartManager({
|
|
121
|
+
runnerName: 'neex start',
|
|
122
|
+
targetFile: file,
|
|
123
|
+
command: startConfig.command,
|
|
124
|
+
processName: startConfig.processName,
|
|
125
|
+
runtime: startConfig.runtime,
|
|
126
|
+
environment: options.environment,
|
|
127
|
+
showInfo: options.info,
|
|
128
|
+
color: !options.color,
|
|
129
|
+
showTiming: !options.timing,
|
|
130
|
+
watch: options.watch,
|
|
131
|
+
delay: parseInt(options.delay),
|
|
132
|
+
verbose: options.verbose,
|
|
133
|
+
cluster: options.cluster,
|
|
134
|
+
clusterInstances: parseInt(options.instances),
|
|
135
|
+
memoryLimit: parseInt(options.memory),
|
|
136
|
+
cpuLimit: parseInt(options.cpu),
|
|
137
|
+
parallel: false,
|
|
138
|
+
printOutput: true,
|
|
139
|
+
prefix: true,
|
|
140
|
+
stopOnError: false,
|
|
141
|
+
minimalOutput: false,
|
|
142
|
+
groupOutput: false,
|
|
143
|
+
isServerMode: true
|
|
144
|
+
});
|
|
145
|
+
// Start the application
|
|
138
146
|
try {
|
|
139
|
-
|
|
147
|
+
if (options.info) {
|
|
148
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Analyzing ${chalk_1.default.cyan(path.basename(file))}`));
|
|
149
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: ${startConfig.runtime} detected, using ${startConfig.runtime} runtime`));
|
|
150
|
+
}
|
|
151
|
+
await startManager.start();
|
|
152
|
+
if (options.info) {
|
|
153
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} Application started successfully`));
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} Application started`));
|
|
157
|
+
}
|
|
140
158
|
}
|
|
141
159
|
catch (error) {
|
|
142
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross}
|
|
160
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Failed to start application`));
|
|
161
|
+
if (error instanceof Error) {
|
|
162
|
+
console.error(chalk_1.default.red(`Error: ${error.message}`));
|
|
163
|
+
}
|
|
143
164
|
process.exit(1);
|
|
144
165
|
}
|
|
145
|
-
// Setup watch configuration if enabled
|
|
146
|
-
const watchPaths = options.watch ? [path.dirname(file)] : [];
|
|
147
|
-
const ignorePatterns = options.ignore || [
|
|
148
|
-
'node_modules/**',
|
|
149
|
-
'.git/**',
|
|
150
|
-
'*.log',
|
|
151
|
-
'src/**',
|
|
152
|
-
'test/**',
|
|
153
|
-
'tests/**',
|
|
154
|
-
'coverage/**',
|
|
155
|
-
'.nyc_output/**',
|
|
156
|
-
'*.tmp',
|
|
157
|
-
'*.temp',
|
|
158
|
-
'.DS_Store',
|
|
159
|
-
'Thumbs.db'
|
|
160
|
-
];
|
|
161
|
-
const extensions = options.ext || ['js', 'mjs', 'json'];
|
|
162
|
-
// Log configuration only if --info flag is set
|
|
163
|
-
if (showInfo) {
|
|
164
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Configuration:`));
|
|
165
|
-
console;
|
|
166
|
-
}
|
|
167
166
|
}
|
|
168
167
|
catch (error) {
|
|
169
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross}
|
|
168
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Failed to start application`));
|
|
169
|
+
if (error instanceof Error) {
|
|
170
|
+
console.error(chalk_1.default.red(`Error: ${error.message}`));
|
|
171
|
+
}
|
|
170
172
|
process.exit(1);
|
|
171
173
|
}
|
|
172
174
|
});
|
|
@@ -45,6 +45,9 @@ class StartManager {
|
|
|
45
45
|
cpuUsage: 0,
|
|
46
46
|
uptime: 0
|
|
47
47
|
};
|
|
48
|
+
if (!options.targetFile || !options.command || !options.processName || !options.runtime) {
|
|
49
|
+
throw new Error('Missing required options: targetFile, command, processName, and runtime are required');
|
|
50
|
+
}
|
|
48
51
|
const defaultOptions = {
|
|
49
52
|
parallel: false,
|
|
50
53
|
printOutput: true,
|
|
@@ -81,10 +84,31 @@ class StartManager {
|
|
|
81
84
|
cluster: false,
|
|
82
85
|
clusterInstances: os.cpus().length
|
|
83
86
|
};
|
|
87
|
+
// Validate numeric values
|
|
88
|
+
const validateNumber = (value, name) => {
|
|
89
|
+
const num = parseInt(value);
|
|
90
|
+
if (isNaN(num) || num < 0) {
|
|
91
|
+
throw new Error(`Invalid ${name}: must be a non-negative number`);
|
|
92
|
+
}
|
|
93
|
+
return num;
|
|
94
|
+
};
|
|
84
95
|
this.options = {
|
|
85
96
|
...defaultOptions,
|
|
86
|
-
...options
|
|
97
|
+
...options,
|
|
98
|
+
delay: validateNumber(options.delay || defaultOptions.delay, 'delay'),
|
|
99
|
+
clusterInstances: validateNumber(options.clusterInstances || defaultOptions.clusterInstances, 'clusterInstances'),
|
|
100
|
+
memoryLimit: options.memoryLimit ? validateNumber(options.memoryLimit, 'memoryLimit') : undefined,
|
|
101
|
+
cpuLimit: options.cpuLimit ? validateNumber(options.cpuLimit, 'cpuLimit') : undefined,
|
|
102
|
+
maxRestarts: options.maxRestarts ? validateNumber(options.maxRestarts, 'maxRestarts') : undefined,
|
|
103
|
+
restartDelay: validateNumber(options.restartDelay || defaultOptions.restartDelay, 'restartDelay')
|
|
87
104
|
};
|
|
105
|
+
// Validate environment
|
|
106
|
+
if (this.options.environment) {
|
|
107
|
+
this.options.environment = this.options.environment.toLowerCase();
|
|
108
|
+
if (!['production', 'development', 'staging', 'test'].includes(this.options.environment)) {
|
|
109
|
+
throw new Error(`Invalid environment: ${this.options.environment}. Must be one of: production, development, staging, test`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
88
112
|
}
|
|
89
113
|
setupFileWatcher() {
|
|
90
114
|
var _a;
|
|
@@ -171,20 +195,59 @@ class StartManager {
|
|
|
171
195
|
logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Application crashed`)}`, 'error');
|
|
172
196
|
logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Attempting restart in ${this.options.restartDelay}ms...`)}`, 'info');
|
|
173
197
|
}
|
|
198
|
+
// Check if we should restart
|
|
199
|
+
if (!this.shouldRestart()) {
|
|
200
|
+
if (this.options.showInfo) {
|
|
201
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Max restarts reached (${this.options.maxRestarts}). Stopping application.`)}`, 'error');
|
|
202
|
+
}
|
|
203
|
+
await this.stop();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
174
206
|
// Wait before restarting
|
|
175
207
|
await new Promise(resolve => setTimeout(resolve, this.options.restartDelay));
|
|
176
|
-
|
|
208
|
+
try {
|
|
209
|
+
await this.gracefulRestart();
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
logger_1.default.printLine(`Failed to restart application: ${error.message}`, 'error');
|
|
213
|
+
if (this.options.stopOnError) {
|
|
214
|
+
await this.stop();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
177
217
|
}
|
|
178
218
|
collectProcessStats() {
|
|
219
|
+
var _a;
|
|
179
220
|
if (!this.options.showInfo) {
|
|
180
221
|
return;
|
|
181
222
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
223
|
+
try {
|
|
224
|
+
const memUsage = process.memoryUsage();
|
|
225
|
+
this.processStats.memoryUsage = Math.round(memUsage.heapUsed / 1024 / 1024);
|
|
226
|
+
this.processStats.uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
227
|
+
// More accurate CPU usage calculation
|
|
228
|
+
const cpuUsage = process.cpuUsage();
|
|
229
|
+
const totalCpuTime = cpuUsage.user + cpuUsage.system;
|
|
230
|
+
const timeDiff = Date.now() - (((_a = this.lastRestartTime) === null || _a === void 0 ? void 0 : _a.getTime()) || this.startTime.getTime());
|
|
231
|
+
this.processStats.cpuUsage = Math.round((totalCpuTime / timeDiff) * 100);
|
|
232
|
+
// Check resource limits
|
|
233
|
+
if (this.options.memoryLimit && this.processStats.memoryUsage > this.options.memoryLimit) {
|
|
234
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
235
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.warning} Memory limit exceeded: ${this.processStats.memoryUsage}MB > ${this.options.memoryLimit}MB`)}`, 'warn');
|
|
236
|
+
if (this.options.stopOnError) {
|
|
237
|
+
this.stop();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (this.options.cpuLimit && this.processStats.cpuUsage > this.options.cpuLimit) {
|
|
241
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
242
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.warning} CPU limit exceeded: ${this.processStats.cpuUsage}% > ${this.options.cpuLimit}%`)}`, 'warn');
|
|
243
|
+
if (this.options.stopOnError) {
|
|
244
|
+
this.stop();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
logger_1.default.printLine(`Failed to collect process stats: ${error.message}`, 'error');
|
|
250
|
+
}
|
|
188
251
|
}
|
|
189
252
|
printStartBanner() {
|
|
190
253
|
var _a, _b;
|
|
@@ -319,6 +382,35 @@ class StartManager {
|
|
|
319
382
|
logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} restarted successfully`)}`, 'info');
|
|
320
383
|
}
|
|
321
384
|
}
|
|
385
|
+
setupGracefulShutdown() {
|
|
386
|
+
const handleSignal = async (signal) => {
|
|
387
|
+
if (!this.isRunning) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
try {
|
|
391
|
+
if (this.options.showInfo) {
|
|
392
|
+
console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Gracefully shutting down ${this.options.processName}...`)}`);
|
|
393
|
+
}
|
|
394
|
+
await this.stop();
|
|
395
|
+
process.exit(0);
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
logger_1.default.printLine(`Failed to handle ${signal}: ${error.message}`, 'error');
|
|
399
|
+
process.exit(1);
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
process.on('SIGINT', () => handleSignal('SIGINT'));
|
|
403
|
+
process.on('SIGTERM', () => handleSignal('SIGTERM'));
|
|
404
|
+
process.on('SIGQUIT', () => handleSignal('SIGQUIT'));
|
|
405
|
+
process.on('uncaughtException', (error) => {
|
|
406
|
+
logger_1.default.printLine(`Uncaught Exception: ${error.message}`, 'error');
|
|
407
|
+
handleSignal('SIGTERM');
|
|
408
|
+
});
|
|
409
|
+
process.on('unhandledRejection', (reason) => {
|
|
410
|
+
logger_1.default.printLine(`Unhandled Rejection: ${reason}`, 'error');
|
|
411
|
+
handleSignal('SIGTERM');
|
|
412
|
+
});
|
|
413
|
+
}
|
|
322
414
|
async stop() {
|
|
323
415
|
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
324
416
|
if (!this.isRunning) {
|
|
@@ -328,34 +420,29 @@ class StartManager {
|
|
|
328
420
|
logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Stopping ${this.options.processName}...`)}`, 'info');
|
|
329
421
|
}
|
|
330
422
|
this.isRunning = false;
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
this.fileWatcher
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
this.runner
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} stopped successfully`)}`, 'info');
|
|
344
|
-
logger_1.default.printLine(`${prefix} Final stats: ${uptimeStr} uptime, ${this.restartCount} restarts, ${this.crashCount} crashes`, 'info');
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
setupGracefulShutdown() {
|
|
348
|
-
const handleSignal = (signal) => {
|
|
423
|
+
try {
|
|
424
|
+
// Stop file watcher
|
|
425
|
+
if (this.fileWatcher) {
|
|
426
|
+
await this.fileWatcher.stop();
|
|
427
|
+
}
|
|
428
|
+
// Stop application gracefully
|
|
429
|
+
if (this.runner) {
|
|
430
|
+
await this.runner.cleanup(this.options.signal);
|
|
431
|
+
}
|
|
432
|
+
// Calculate final stats
|
|
433
|
+
const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
434
|
+
const uptimeStr = this.formatUptime(uptime);
|
|
349
435
|
if (this.options.showInfo) {
|
|
350
|
-
|
|
436
|
+
logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} stopped successfully`)}`, 'info');
|
|
437
|
+
logger_1.default.printLine(`${prefix} Final stats: ${uptimeStr} uptime, ${this.restartCount} restarts, ${this.crashCount} crashes`, 'info');
|
|
351
438
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
logger_1.default.printLine(`Failed to stop application: ${error.message}`, 'error');
|
|
442
|
+
if (this.options.stopOnError) {
|
|
443
|
+
process.exit(1);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
359
446
|
}
|
|
360
447
|
isActive() {
|
|
361
448
|
return this.isRunning;
|