fix(core): Improve error handling, logging, and test suite; update dependency versions
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import { EventEmitter } from 'events';
|
||||
import { Logger, ProcessError, handleError } from './utils.errorhandler.js';
|
||||
|
||||
export interface IProcessWrapperOptions {
|
||||
command: string;
|
||||
@@ -22,11 +23,13 @@ export class ProcessWrapper extends EventEmitter {
|
||||
private logs: IProcessLog[] = [];
|
||||
private logBufferSize: number;
|
||||
private startTime: Date | null = null;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(options: IProcessWrapperOptions) {
|
||||
super();
|
||||
this.options = options;
|
||||
this.logBufferSize = options.logBuffer || 100;
|
||||
this.logger = new Logger(`ProcessWrapper:${options.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,6 +39,8 @@ export class ProcessWrapper extends EventEmitter {
|
||||
this.addSystemLog('Starting process...');
|
||||
|
||||
try {
|
||||
this.logger.debug(`Starting process: ${this.options.command}`);
|
||||
|
||||
if (this.options.args && this.options.args.length > 0) {
|
||||
this.process = plugins.childProcess.spawn(this.options.command, this.options.args, {
|
||||
cwd: this.options.cwd,
|
||||
@@ -56,14 +61,22 @@ export class ProcessWrapper extends EventEmitter {
|
||||
|
||||
// Handle process exit
|
||||
this.process.on('exit', (code, signal) => {
|
||||
this.addSystemLog(`Process exited with code ${code}, signal ${signal}`);
|
||||
const exitMessage = `Process exited with code ${code}, signal ${signal}`;
|
||||
this.logger.info(exitMessage);
|
||||
this.addSystemLog(exitMessage);
|
||||
this.emit('exit', code, signal);
|
||||
});
|
||||
|
||||
// Handle errors
|
||||
this.process.on('error', (error) => {
|
||||
this.addSystemLog(`Process error: ${error.message}`);
|
||||
this.emit('error', error);
|
||||
const processError = new ProcessError(
|
||||
error.message,
|
||||
'ERR_PROCESS_EXECUTION',
|
||||
{ command: this.options.command, pid: this.process?.pid }
|
||||
);
|
||||
this.logger.error(processError);
|
||||
this.addSystemLog(`Process error: ${processError.toString()}`);
|
||||
this.emit('error', processError);
|
||||
});
|
||||
|
||||
// Capture stdout
|
||||
@@ -91,12 +104,22 @@ export class ProcessWrapper extends EventEmitter {
|
||||
}
|
||||
|
||||
this.addSystemLog(`Process started with PID ${this.process.pid}`);
|
||||
this.logger.info(`Process started with PID ${this.process.pid}`);
|
||||
this.emit('start', this.process.pid);
|
||||
|
||||
} catch (error) {
|
||||
this.addSystemLog(`Failed to start process: ${error.message}`);
|
||||
this.emit('error', error);
|
||||
throw error;
|
||||
} catch (error: Error | unknown) {
|
||||
const processError = error instanceof ProcessError
|
||||
? error
|
||||
: new ProcessError(
|
||||
error instanceof Error ? error.message : String(error),
|
||||
'ERR_PROCESS_START_FAILED',
|
||||
{ command: this.options.command }
|
||||
);
|
||||
|
||||
this.logger.error(processError);
|
||||
this.addSystemLog(`Failed to start process: ${processError.toString()}`);
|
||||
this.emit('error', processError);
|
||||
throw processError;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,30 +128,43 @@ export class ProcessWrapper extends EventEmitter {
|
||||
*/
|
||||
public stop(): void {
|
||||
if (!this.process) {
|
||||
this.logger.debug('Stop called but no process is running');
|
||||
this.addSystemLog('No process running');
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.info('Stopping process...');
|
||||
this.addSystemLog('Stopping process...');
|
||||
|
||||
// First try SIGTERM for graceful shutdown
|
||||
if (this.process.pid) {
|
||||
try {
|
||||
this.logger.debug(`Sending SIGTERM to process ${this.process.pid}`);
|
||||
process.kill(this.process.pid, 'SIGTERM');
|
||||
|
||||
// Give it 5 seconds to shut down gracefully
|
||||
setTimeout(() => {
|
||||
setTimeout((): void => {
|
||||
if (this.process && this.process.pid) {
|
||||
this.logger.warn(`Process ${this.process.pid} did not exit gracefully, force killing...`);
|
||||
this.addSystemLog('Process did not exit gracefully, force killing...');
|
||||
try {
|
||||
process.kill(this.process.pid, 'SIGKILL');
|
||||
} catch (error) {
|
||||
} catch (error: Error | unknown) {
|
||||
// Process might have exited between checks
|
||||
this.logger.debug(`Failed to send SIGKILL, process probably already exited: ${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
}`);
|
||||
}
|
||||
}
|
||||
}, 5000);
|
||||
} catch (error) {
|
||||
this.addSystemLog(`Error stopping process: ${error.message}`);
|
||||
} catch (error: Error | unknown) {
|
||||
const processError = new ProcessError(
|
||||
error instanceof Error ? error.message : String(error),
|
||||
'ERR_PROCESS_STOP_FAILED',
|
||||
{ pid: this.process.pid }
|
||||
);
|
||||
this.logger.error(processError);
|
||||
this.addSystemLog(`Error stopping process: ${processError.toString()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user