6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
8
import { SpawnOptions , spawn } from 'child_process' ;
9
+ import * as pidusage from 'pidusage' ;
9
10
import { Observable , Subject , from , timer } from 'rxjs' ;
10
11
import { concatMap , map , onErrorResumeNext , tap } from 'rxjs/operators' ;
11
12
import { Command } from './command' ;
12
13
import { AggregatedProcessStats , MonitoredProcess } from './interfaces' ;
13
- const pidusage = require ( 'pidusage' ) ;
14
+
14
15
const pidtree = require ( 'pidtree' ) ;
15
16
const treeKill = require ( 'tree-kill' ) ;
16
17
17
-
18
18
// Cleanup when the parent process exits.
19
19
const defaultProcessExitCb = ( ) => { } ;
20
20
let processExitCb = defaultProcessExitCb ;
@@ -28,10 +28,11 @@ export class LocalMonitoredProcess implements MonitoredProcess {
28
28
private stdout = new Subject < Buffer > ( ) ;
29
29
private stderr = new Subject < Buffer > ( ) ;
30
30
private pollingRate = 100 ;
31
+ private elapsedTimer = 0 ;
32
+
31
33
stats$ : Observable < AggregatedProcessStats > = this . stats . asObservable ( ) ;
32
34
stdout$ : Observable < Buffer > = this . stdout . asObservable ( ) ;
33
35
stderr$ : Observable < Buffer > = this . stderr . asObservable ( ) ;
34
- private elapsedTimer : number ;
35
36
36
37
constructor (
37
38
private command : Command ,
@@ -52,24 +53,27 @@ export class LocalMonitoredProcess implements MonitoredProcess {
52
53
// Emit output and stats.
53
54
childProcess . stdout . on ( 'data' , ( data : Buffer ) => this . stdout . next ( data ) ) ;
54
55
childProcess . stderr . on ( 'data' , ( data : Buffer ) => this . stderr . next ( data ) ) ;
56
+
55
57
const statsSubs = timer ( 0 , this . pollingRate ) . pipe (
56
- concatMap ( ( ) => from ( pidtree ( childProcess . pid , { root : true } ) ) ) ,
58
+ concatMap ( ( ) => from ( pidtree ( childProcess . pid , { root : true } ) as Promise < number [ ] > ) ) ,
57
59
concatMap ( ( pids : number [ ] ) => from ( pidusage ( pids , { maxage : 5 * this . pollingRate } ) ) ) ,
58
- map ( ( statsByProcess : { [ key : string ] : AggregatedProcessStats } ) => {
60
+ map ( statsByProcess => {
59
61
// Ignore the spawned shell in the total process number.
60
62
const pids = Object . keys ( statsByProcess )
61
63
. filter ( pid => pid != childProcess . pid . toString ( ) ) ;
62
64
const processes = pids . length ;
63
65
// We want most stats from the parent process.
64
66
const { pid, ppid, ctime, elapsed, timestamp } = statsByProcess [ childProcess . pid ] ;
67
+
65
68
// CPU and memory should be agreggated.
66
- let cpu = 0 , memory = 0 ;
69
+ let cpu = 0 ;
70
+ let memory = 0 ;
67
71
for ( const pid of pids ) {
68
72
cpu += statsByProcess [ pid ] . cpu ;
69
73
memory += statsByProcess [ pid ] . memory ;
70
74
}
71
75
72
- return {
76
+ const stats : AggregatedProcessStats = {
73
77
processes,
74
78
cpu,
75
79
memory,
@@ -78,7 +82,9 @@ export class LocalMonitoredProcess implements MonitoredProcess {
78
82
ctime,
79
83
elapsed : this . useProcessTime ? elapsed : ( Date . now ( ) - this . elapsedTimer ) ,
80
84
timestamp,
81
- } as AggregatedProcessStats ;
85
+ } ;
86
+
87
+ return stats ;
82
88
} ) ,
83
89
tap ( stats => this . stats . next ( stats ) ) ,
84
90
onErrorResumeNext ( ) ,
0 commit comments