@@ -62,45 +62,53 @@ export interface ChildProcessResult {
62
62
signal ?: string
63
63
}
64
64
65
+ interface Tracker < T > {
66
+ add ( item : T ) : void
67
+ delete ( item : T ) : void
68
+ has ( item : T ) : boolean
69
+ size ( ) : number
70
+ cleanUp ( ) : void
71
+ monitor ( ) : void | Promise < void >
72
+ }
73
+
65
74
export const eof = Symbol ( 'EOF' )
66
75
67
- class ChildProcessTracker extends Map < number , ChildProcess > {
68
- static pollingInterval : number = 1000
76
+ export class ChildProcessTracker implements Tracker < ChildProcess > {
77
+ static pollingInterval : number = 10000
69
78
static thresholds : { memory : number ; cpu : number ; time : number } = {
70
79
memory : 100 * 1024 * 1024 , // 100 MB
71
80
cpu : 50 ,
72
81
time : 30 * 1000 , // 30 seconds
73
82
}
74
-
75
- #processPoller : PollingSet < number >
83
+ #processByPid: Map < number , ChildProcess > = new Map < number , ChildProcess > ( )
84
+ #pids : PollingSet < number >
76
85
77
86
public constructor ( ) {
78
- super ( )
79
- this . #processPoller = new PollingSet ( ChildProcessTracker . pollingInterval , ( ) => this . monitorProcesses ( ) )
87
+ this . #pids = new PollingSet ( ChildProcessTracker . pollingInterval , ( ) => this . monitor ( ) )
80
88
getLogger ( ) . debug ( `ChildProcessTracker created with polling interval: ${ ChildProcessTracker . pollingInterval } ` )
81
89
}
82
90
83
- private cleanUpProcesses ( ) {
84
- const terminatedProcesses = Array . from ( this . #processPoller . values ( ) ) . filter (
85
- ( pid : number ) => ! this . has ( pid ) || this . get ( pid ) ?. stopped
91
+ public cleanUp ( ) {
92
+ const terminatedProcesses = Array . from ( this . #pids . values ( ) ) . filter (
93
+ ( pid : number ) => ! this . #pids . has ( pid ) || this . #processByPid . get ( pid ) ?. stopped
86
94
)
87
95
for ( const pid of terminatedProcesses ) {
88
- this . #processPoller . delete ( pid )
96
+ this . #pids . delete ( pid )
89
97
}
90
98
}
91
99
92
- public async monitorProcesses ( ) {
93
- this . cleanUpProcesses ( )
94
- getLogger ( ) . debug ( `Active running processes size: ${ this . #processPoller . size } ` )
100
+ public async monitor ( ) {
101
+ this . cleanUp ( )
102
+ getLogger ( ) . debug ( `Active running processes size: ${ this . #pids . size } ` )
95
103
96
- for ( const pid of this . #processPoller . values ( ) ) {
97
- await this . monitorProcess ( pid )
104
+ for ( const pid of this . #pids . values ( ) ) {
105
+ await this . checkProcessUsage ( pid )
98
106
}
99
107
}
100
108
101
- private async monitorProcess ( pid : number ) {
102
- if ( this . has ( pid ) ) {
103
- const stats = await pidusage ( pid )
109
+ private async checkProcessUsage ( pid : number ) : Promise < void > {
110
+ if ( this . #pids . has ( pid ) ) {
111
+ const stats = await this . getUsage ( pid )
104
112
getLogger ( ) . debug ( `stats for ${ pid } : %O` , stats )
105
113
if ( stats . memory > ChildProcessTracker . thresholds . memory ) {
106
114
getLogger ( ) . warn ( `Process ${ pid } exceeded memory threshold: ${ stats . memory } ` )
@@ -116,20 +124,33 @@ class ChildProcessTracker extends Map<number, ChildProcess> {
116
124
}
117
125
}
118
126
119
- public override set ( key : number , value : ChildProcess ) : this {
120
- this . #processPoller. start ( key )
121
- super . set ( key , value )
122
- return this
127
+ public add ( childProcess : ChildProcess ) {
128
+ const pid = childProcess . pid ( )
129
+ this . #processByPid. set ( pid , childProcess )
130
+ this . #pids. start ( pid )
131
+ }
132
+
133
+ public delete ( childProcess : ChildProcess ) {
134
+ const pid = childProcess . pid ( )
135
+ this . #processByPid. delete ( pid )
136
+ this . #pids. delete ( pid )
123
137
}
124
138
125
- public override delete ( key : number ) : boolean {
126
- this . #processPoller. delete ( key )
127
- return super . delete ( key )
139
+ public size ( ) {
140
+ return this . #pids. size
128
141
}
129
142
130
- public override clear ( ) : void {
131
- this . #processPoller. clear ( )
132
- super . clear ( )
143
+ public has ( childProcess : ChildProcess ) {
144
+ return this . #pids. has ( childProcess . pid ( ) )
145
+ }
146
+
147
+ private async getUsage ( pid : number ) : Promise < { memory : number ; cpu : number ; elapsed : number } > {
148
+ const stats = await pidusage ( pid )
149
+ return {
150
+ memory : stats . memory ,
151
+ cpu : stats . cpu ,
152
+ elapsed : stats . elapsed ,
153
+ }
133
154
}
134
155
}
135
156
@@ -140,7 +161,7 @@ class ChildProcessTracker extends Map<number, ChildProcess> {
140
161
* - call and await run to get the results (pass or fail)
141
162
*/
142
163
export class ChildProcess {
143
- static #runningProcesses: ChildProcessTracker = new ChildProcessTracker ( )
164
+ static #runningProcesses: Tracker < ChildProcess > = new ChildProcessTracker ( )
144
165
#childProcess: proc . ChildProcess | undefined
145
166
#processErrors: Error [ ] = [ ]
146
167
#processResult: ChildProcessResult | undefined
@@ -213,7 +234,7 @@ export class ChildProcess {
213
234
const args = this . #args. concat ( options . extraArgs ?? [ ] )
214
235
215
236
const debugDetail = this . #log. logLevelEnabled ( 'debug' )
216
- ? ` (running processes: ${ ChildProcess . #runningProcesses. size } )`
237
+ ? ` (running processes: ${ ChildProcess . #runningProcesses. size ( ) } )`
217
238
: ''
218
239
this . #log. info ( `Command: ${ this . toString ( options . logging === 'noparams' ) } ${ debugDetail } ` )
219
240
@@ -381,7 +402,7 @@ export class ChildProcess {
381
402
if ( pid === undefined ) {
382
403
return
383
404
}
384
- ChildProcess . #runningProcesses. set ( pid , this )
405
+ ChildProcess . #runningProcesses. add ( this )
385
406
386
407
const timeoutListener = options ?. timeout ?. token . onCancellationRequested ( ( { agent } ) => {
387
408
const message = agent === 'user' ? 'Cancelled: ' : 'Timed out: '
@@ -391,7 +412,7 @@ export class ChildProcess {
391
412
392
413
const dispose = ( ) => {
393
414
timeoutListener ?. dispose ( )
394
- ChildProcess . #runningProcesses. delete ( pid )
415
+ ChildProcess . #runningProcesses. delete ( this )
395
416
}
396
417
397
418
process . on ( 'exit' , dispose )
0 commit comments