Implement smarter process kill when in npm mode with watch changes
All checks were successful
continuous-integration/appveyor/branch AppVeyor build succeeded
All checks were successful
continuous-integration/appveyor/branch AppVeyor build succeeded
This commit is contained in:
parent
18f9806135
commit
a70d64e624
4 changed files with 77 additions and 9 deletions
|
@ -3,6 +3,7 @@ import fs from 'fs'
|
||||||
import fsPromise from 'fs/promises'
|
import fsPromise from 'fs/promises'
|
||||||
import cluster from 'cluster'
|
import cluster from 'cluster'
|
||||||
import child_process from 'child_process'
|
import child_process from 'child_process'
|
||||||
|
import kill from './kill.mjs'
|
||||||
import Watcher, { EVENT_REMOVE, EVENT_UPDATE } from './watch/index.mjs'
|
import Watcher, { EVENT_REMOVE, EVENT_UPDATE } from './watch/index.mjs'
|
||||||
|
|
||||||
export const MESSAGE_FILES_REQUEST = 'message_files_request'
|
export const MESSAGE_FILES_REQUEST = 'message_files_request'
|
||||||
|
@ -41,6 +42,7 @@ export function CLI(e, overrides = {}) {
|
||||||
this.logger = overrides.logger || console
|
this.logger = overrides.logger || console
|
||||||
this.child_process = overrides.child_process || child_process
|
this.child_process = overrides.child_process || child_process
|
||||||
this.process = overrides.process || process
|
this.process = overrides.process || process
|
||||||
|
this.kill = overrides.kill || kill
|
||||||
this.importer = overrides.importer
|
this.importer = overrides.importer
|
||||||
this.loadDefaults()
|
this.loadDefaults()
|
||||||
}
|
}
|
||||||
|
@ -287,7 +289,7 @@ CLI.prototype.runProgram = function() {
|
||||||
if (runningTest) {
|
if (runningTest) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
this.worker.kill()
|
this.kill(this.worker.pid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
59
lib/kill.mjs
Normal file
59
lib/kill.mjs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import { promisify } from 'util'
|
||||||
|
import { spawn, exec } from 'child_process'
|
||||||
|
|
||||||
|
const execPromise = promisify(exec)
|
||||||
|
|
||||||
|
export default function kill(pid, signal) {
|
||||||
|
let pids = new Set()
|
||||||
|
let getSpawn = null
|
||||||
|
|
||||||
|
switch (process.platform) {
|
||||||
|
case 'win32':
|
||||||
|
return execPromise('taskkill /pid ' + pid + ' /T /F')
|
||||||
|
case 'darwin':
|
||||||
|
getSpawn = function(parentPid) {
|
||||||
|
return spawn('pgrep', ['-P', parentPid])
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
getSpawn = function (parentPid) {
|
||||||
|
return spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid])
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildTree(pids, getSpawn, pid)
|
||||||
|
.then(function() {
|
||||||
|
for (let pid of pids) {
|
||||||
|
try {
|
||||||
|
process.kill(pid, signal)
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code !== 'ESRCH') throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTree(allPids, spawnGetChildren, parentPid) {
|
||||||
|
allPids.set(parentPid)
|
||||||
|
|
||||||
|
let ps = spawnGetChildren(parentPid)
|
||||||
|
let data = ''
|
||||||
|
ps.stdout.on('data', function(buf) {
|
||||||
|
data += buf.toString('ascii')
|
||||||
|
})
|
||||||
|
|
||||||
|
return new Promise(function(res) {
|
||||||
|
ps.on('close', function(code) {
|
||||||
|
// Check if we got error code (usually means empty results)
|
||||||
|
if (code !== 0) return res()
|
||||||
|
|
||||||
|
res(Promise.all(
|
||||||
|
allData.match(/\d+/g)
|
||||||
|
.map(Number)
|
||||||
|
.filter(pid => !bla.has(pid))
|
||||||
|
.map(buildTree.bind(this, allPids, spawnGetChildren))
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "eltro",
|
"name": "eltro",
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"description": "Eltro is a tiny no-dependancy test framework for node",
|
"description": "Eltro is a tiny no-dependancy test framework for node",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -26,8 +26,9 @@ t.describe('CLI', function() {
|
||||||
const cluster = { c: 3 }
|
const cluster = { c: 3 }
|
||||||
const process = { d: 4 }
|
const process = { d: 4 }
|
||||||
const importer = { e: 5 }
|
const importer = { e: 5 }
|
||||||
|
const kill = { f: 6 }
|
||||||
|
|
||||||
let cliTest = createSafeCli(eltro, { logger, cluster, process, importer })
|
let cliTest = createSafeCli(eltro, { logger, cluster, process, importer, kill })
|
||||||
assert.strictEqual(cliTest.reporter, 'list')
|
assert.strictEqual(cliTest.reporter, 'list')
|
||||||
assert.strictEqual(cliTest.ignoreOnly, false)
|
assert.strictEqual(cliTest.ignoreOnly, false)
|
||||||
assert.strictEqual(cliTest.timeout, 2000)
|
assert.strictEqual(cliTest.timeout, 2000)
|
||||||
|
@ -43,6 +44,7 @@ t.describe('CLI', function() {
|
||||||
assert.strictEqual(cliTest.cluster, cluster)
|
assert.strictEqual(cliTest.cluster, cluster)
|
||||||
assert.strictEqual(cliTest.process, process)
|
assert.strictEqual(cliTest.process, process)
|
||||||
assert.strictEqual(cliTest.importer, importer)
|
assert.strictEqual(cliTest.importer, importer)
|
||||||
|
assert.strictEqual(cliTest.kill, kill)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should detect isSlave from cluster', function() {
|
t.test('should detect isSlave from cluster', function() {
|
||||||
|
@ -913,14 +915,16 @@ t.describe('CLI', function() {
|
||||||
let testCluster
|
let testCluster
|
||||||
let testChildProcess
|
let testChildProcess
|
||||||
let testWorker
|
let testWorker
|
||||||
|
let testKill
|
||||||
let cli
|
let cli
|
||||||
|
|
||||||
t.beforeEach(function() {
|
t.beforeEach(function() {
|
||||||
|
testKill = stub()
|
||||||
testProcess = { stdout: { write: stub() }, stderr: { write: stub() } }
|
testProcess = { stdout: { write: stub() }, stderr: { write: stub() } }
|
||||||
testWorker = { on: stub(), once: stub(), kill: stub(), send: stub(), stderr: { on: stub() }, stdout: { on: stub() } }
|
testWorker = { on: stub(), once: stub(), send: stub(), stderr: { on: stub() }, stdout: { on: stub() } }
|
||||||
testCluster = { fork: stub().returns(testWorker) }
|
testCluster = { fork: stub().returns(testWorker) }
|
||||||
testChildProcess = { spawn: stub().returns(testWorker) }
|
testChildProcess = { spawn: stub().returns(testWorker) }
|
||||||
cli = createSafeCli(null, { cluster: testCluster, child_process: testChildProcess, process: testProcess })
|
cli = createSafeCli(null, { cluster: testCluster, child_process: testChildProcess, process: testProcess, kill: testKill })
|
||||||
})
|
})
|
||||||
|
|
||||||
t.describe('in test mode', function() {
|
t.describe('in test mode', function() {
|
||||||
|
@ -984,14 +988,14 @@ t.describe('CLI', function() {
|
||||||
t.test('multiple calls should cancel', function() {
|
t.test('multiple calls should cancel', function() {
|
||||||
cli.runProgram()
|
cli.runProgram()
|
||||||
|
|
||||||
assert.notOk(testWorker.kill.called)
|
assert.notOk(testKill.called)
|
||||||
assert.ok(testCluster.fork.called)
|
assert.ok(testCluster.fork.called)
|
||||||
testCluster.fork.reset()
|
testCluster.fork.reset()
|
||||||
|
|
||||||
cli.runProgram()
|
cli.runProgram()
|
||||||
|
|
||||||
assert.notOk(testCluster.fork.called)
|
assert.notOk(testCluster.fork.called)
|
||||||
assert.notOk(testWorker.kill.called)
|
assert.notOk(testKill.called)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1063,16 +1067,19 @@ t.describe('CLI', function() {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('multiple calls should kill', function() {
|
t.test('multiple calls should kill', function() {
|
||||||
|
const assertPid = 12345235
|
||||||
|
testWorker.pid = assertPid
|
||||||
cli.runProgram()
|
cli.runProgram()
|
||||||
|
|
||||||
assert.notOk(testWorker.kill.called)
|
assert.notOk(testKill.called)
|
||||||
assert.ok(testChildProcess.spawn.called)
|
assert.ok(testChildProcess.spawn.called)
|
||||||
testChildProcess.spawn.reset().returns(testWorker)
|
testChildProcess.spawn.reset().returns(testWorker)
|
||||||
|
|
||||||
cli.runProgram()
|
cli.runProgram()
|
||||||
|
|
||||||
assert.ok(testChildProcess.spawn.called)
|
assert.ok(testChildProcess.spawn.called)
|
||||||
assert.ok(testWorker.kill.called)
|
assert.ok(testKill.called)
|
||||||
|
assert.strictEqual(testKill.firstCall[0], assertPid)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue