feat(core): Introduce ProcessMonitor with memory management and spawning features

This commit is contained in:
2025-03-01 18:02:40 +00:00
parent 36eb1a79a7
commit ad2c180cfe
9 changed files with 140 additions and 34 deletions

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@git.zone/tspm',
version: '1.1.1',
version: '1.2.0',
description: 'a no fuzz process manager'
}

View File

@ -1,8 +1,6 @@
import { spawn, ChildProcess } from 'child_process';
import psTree from 'ps-tree';
import pidusage from 'pidusage';
import * as plugins from './plugins.js';
interface IMonitorConfig {
export interface IMonitorConfig {
name?: string; // Optional name to identify the instance
projectDir: string; // Directory where the command will run
command: string; // Full command to run (e.g., "npm run xyz")
@ -11,8 +9,8 @@ interface IMonitorConfig {
monitorIntervalMs?: number; // Interval (in ms) at which memory is checked (default: 5000)
}
class ProcessMonitor {
private child: ChildProcess | null = null;
export class ProcessMonitor {
private child: plugins.childProcess.ChildProcess | null = null;
private config: IMonitorConfig;
private intervalId: NodeJS.Timeout | null = null;
private stopped: boolean = true; // Initially stopped until start() is called
@ -46,7 +44,7 @@ class ProcessMonitor {
', '
)}] in directory: ${this.config.projectDir}`
);
this.child = spawn(this.config.command, this.config.args, {
this.child = plugins.childProcess.spawn(this.config.command, this.config.args, {
cwd: this.config.projectDir,
detached: true,
stdio: 'inherit',
@ -56,7 +54,7 @@ class ProcessMonitor {
`Spawning command "${this.config.command}" in directory: ${this.config.projectDir}`
);
// Use shell mode to allow a full command string.
this.child = spawn(this.config.command, {
this.child = plugins.childProcess.spawn(this.config.command, {
cwd: this.config.projectDir,
detached: true,
stdio: 'inherit',
@ -107,11 +105,11 @@ class ProcessMonitor {
*/
private getProcessGroupMemory(pid: number): Promise<number> {
return new Promise((resolve, reject) => {
psTree(pid, (err, children) => {
plugins.psTree(pid, (err, children) => {
if (err) return reject(err);
// Include the main process and its children.
const pids: number[] = [pid, ...children.map(child => Number(child.PID))];
pidusage(pids, (err, stats) => {
plugins.pidusage(pids, (err, stats) => {
if (err) return reject(err);
let totalMemory = 0;
for (const key in stats) {
@ -157,22 +155,3 @@ class ProcessMonitor {
console.log(prefix + message);
}
}
// Example usage:
const config: IMonitorConfig = {
name: 'Project XYZ Monitor', // Identifier for the instance
projectDir: '/path/to/your/project', // Set the project directory here
command: 'npm run xyz', // Full command string (no need for args)
memoryLimitBytes: 500 * 1024 * 1024, // 500 MB memory limit
monitorIntervalMs: 5000, // Check memory usage every 5 seconds
};
const monitor = new ProcessMonitor(config);
monitor.start();
// Ensure that on process exit (e.g. Ctrl+C) we clean up the child process and prevent respawns.
process.on('SIGINT', () => {
monitor.log('Received SIGINT, stopping monitor...');
monitor.stop();
process.exit();
});

View File

@ -1,3 +1,2 @@
import * as plugins from './plugins.js';
export let demoExport = 'Hi there! :) This is an exported string';
export * from './classes.tspm.js';
export * from './classes.processmonitor.js';

4
ts/paths.ts Normal file
View File

@ -0,0 +1,4 @@
import * as plugins from './plugins.js';
export const packageDir = plugins.path.join(plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url), '..');
export const cwd = process.cwd();

View File

@ -1,13 +1,26 @@
// native scope
import * as childProcess from 'child_process';
import * as path from 'node:path';
export {
childProcess,
path,
}
// @push.rocks scope
import * as smartpath from '@push.rocks/smartpath';
import * as smartcli from '@push.rocks/smartcli';
export {
smartpath,
smartcli,
}
// third-party scope
import psTree from 'ps-tree';
import pidusage from 'pidusage';
export {
psTree,
pidusage,
}