1 | const assert = require('assert')
|
2 | const events = require('events')
|
3 | const Isochronous = require('isochronous')
|
4 | const isRunning = require('is-running')
|
5 |
|
6 | class Killer extends events.EventEmitter {
|
7 | constructor (interval, printer = { say: () => {} }) {
|
8 | super()
|
9 | this._isochronous = new Isochronous(interval, true, async () => {
|
10 | let i = 0, I = this._pids.length
|
11 | while (i < I) {
|
12 | const pid = this._pids[i]
|
13 | printer.say('liveness', { pid })
|
14 | if (!isRunning(pid)) {
|
15 | this.emit('killed', pid)
|
16 | this._pids.splice(i, 1)
|
17 | I--
|
18 | } else {
|
19 | i++
|
20 | }
|
21 | }
|
22 | if (this._pids.length == 0) {
|
23 | this._clean()
|
24 | }
|
25 | await this._unlatched
|
26 | })
|
27 | this.destroyed = false
|
28 | this._pids = []
|
29 | this._exited = {}
|
30 | this._clean()
|
31 | }
|
32 |
|
33 | _clean () {
|
34 | this._unlatched = new Promise(resolve => this._latch = resolve)
|
35 | }
|
36 |
|
37 | run () {
|
38 | return this._isochronous.start()
|
39 | }
|
40 |
|
41 | exited (pid) {
|
42 | assert(this._pids.filter(p => p == pid).length == 0)
|
43 | delete this._exited[pid]
|
44 | }
|
45 |
|
46 | unwatch (pid) {
|
47 | const index = this._pids.indexOf(pid)
|
48 | if (~index) {
|
49 | this._pids.splice(index, 1)
|
50 | }
|
51 | delete this._exited[pid]
|
52 | }
|
53 |
|
54 | watch (pid) {
|
55 | assert(!this.destroyed)
|
56 | if (this._exited[pid] == null) {
|
57 | this._exited[pid] = pid
|
58 | this._pids.push(pid)
|
59 | this._latch.call()
|
60 | }
|
61 | }
|
62 |
|
63 | destroy () {
|
64 | if (!this.destroyed) {
|
65 | this.destroyed = true
|
66 | this._isochronous.stop()
|
67 | this._latch.call()
|
68 | }
|
69 | }
|
70 | }
|
71 |
|
72 | module.exports = Killer
|