mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* [kbn-dev-utils/procRunner] try using execa to avoid never-exitting procs * [kbn-dev-utils/procRunner] don't listen for close event, rely on stdio streams ending
This commit is contained in:
parent
d6a823e62d
commit
b36e7aff43
4 changed files with 111 additions and 55 deletions
|
@ -10,15 +10,14 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"chalk": "^2.3.0",
|
||||
"execa": "^0.10.0",
|
||||
"moment": "^2.20.1",
|
||||
"tree-kill": "1.1.0"
|
||||
"tree-kill": "^1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.26.0",
|
||||
"@kbn/babel-preset": "link:../kbn-babel-preset",
|
||||
"babel-cli": "^6.26.0",
|
||||
"chance": "1.0.6",
|
||||
"expect.js": "0.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
import Rx from 'rxjs/Rx';
|
||||
|
||||
import { createCliError } from './errors';
|
||||
|
||||
/**
|
||||
* Creates an Observable from a childProcess that:
|
||||
* - provides the exit code as it's only value (which may be null)
|
||||
* as soon as the process exits
|
||||
* - completes once all stdio streams for the child process have closed
|
||||
* - fails if the childProcess emits an error event
|
||||
*
|
||||
* @param {ChildProcess} childProcess
|
||||
* @return {Rx.Observable}
|
||||
*/
|
||||
export function observeChildProcess(name, childProcess) {
|
||||
// observe first exit event
|
||||
const exit$ = Rx.Observable.fromEvent(childProcess, 'exit')
|
||||
.first()
|
||||
.map(code => {
|
||||
// JVM exits with 143 on SIGTERM and 130 on SIGINT, dont' treat then as errors
|
||||
if (code > 0 && !(code === 143 || code === 130)) {
|
||||
throw createCliError(`[${name}] exitted with code ${code}`);
|
||||
}
|
||||
|
||||
return code;
|
||||
});
|
||||
|
||||
// observe first close event
|
||||
const close$ = Rx.Observable.fromEvent(childProcess, 'close').first();
|
||||
|
||||
// observe first error event until there is a close event
|
||||
const error$ = Rx.Observable.fromEvent(childProcess, 'error')
|
||||
.first()
|
||||
.mergeMap(err => Rx.Observable.throw(err))
|
||||
.takeUntil(close$);
|
||||
|
||||
return Rx.Observable.merge(exit$, close$.ignoreElements(), error$);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { spawn } from 'child_process';
|
||||
import execa from 'execa';
|
||||
import { statSync } from 'fs';
|
||||
|
||||
import Rx from 'rxjs/Rx';
|
||||
|
@ -10,7 +10,7 @@ const treeKillAsync = promisify(treeKill);
|
|||
|
||||
import { log } from './log';
|
||||
import { observeLines } from './observe_lines';
|
||||
import { observeChildProcess } from './observe_child_process';
|
||||
import { createCliError } from './errors';
|
||||
|
||||
const SECOND = 1000;
|
||||
const STOP_TIMEOUT = 30 * SECOND;
|
||||
|
@ -50,14 +50,16 @@ export function createProc(name, { cmd, args, cwd, env, stdin }) {
|
|||
}
|
||||
}
|
||||
|
||||
const childProcess = spawn(cmd, args, {
|
||||
const childProcess = execa(cmd, args, {
|
||||
cwd,
|
||||
env,
|
||||
stdio: [stdin ? 'pipe' : 'ignore', 'pipe', 'pipe'],
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
if (stdin) {
|
||||
childProcess.stdin.end(stdin, 'utf8');
|
||||
} else {
|
||||
childProcess.stdin.end();
|
||||
}
|
||||
|
||||
return new class Proc {
|
||||
|
@ -70,15 +72,32 @@ export function createProc(name, { cmd, args, cwd, env, stdin }) {
|
|||
.do(line => log.write(` ${gray('proc')} [${gray(name)}] ${line}`))
|
||||
.share();
|
||||
|
||||
outcome$ = observeChildProcess(name, childProcess).share();
|
||||
outcome$ = Rx.Observable.defer(() => {
|
||||
// observe first exit event
|
||||
const exit$ = Rx.Observable.fromEvent(childProcess, 'exit')
|
||||
.take(1)
|
||||
.map(code => {
|
||||
// JVM exits with 143 on SIGTERM and 130 on SIGINT, dont' treat then as errors
|
||||
if (code > 0 && !(code === 143 || code === 130)) {
|
||||
throw createCliError(`[${name}] exitted with code ${code}`);
|
||||
}
|
||||
|
||||
return code;
|
||||
});
|
||||
|
||||
// observe first error event until there is a close event
|
||||
const error$ = Rx.Observable.fromEvent(childProcess, 'error')
|
||||
.take(1)
|
||||
.mergeMap(err => Rx.Observable.throw(err));
|
||||
|
||||
return Rx.Observable.race(exit$, error$);
|
||||
}).share()
|
||||
|
||||
outcomePromise = Rx.Observable.merge(
|
||||
this.lines$.ignoreElements(),
|
||||
this.outcome$
|
||||
).toPromise();
|
||||
|
||||
closedPromise = this.outcomePromise.then(() => {}, () => {});
|
||||
|
||||
async stop(signal) {
|
||||
await withTimeout(
|
||||
async () => {
|
||||
|
@ -93,11 +112,15 @@ export function createProc(name, { cmd, args, cwd, env, stdin }) {
|
|||
|
||||
await withTimeout(
|
||||
async () => {
|
||||
await this.closedPromise;
|
||||
try {
|
||||
await this.outcomePromise;
|
||||
} catch (error) {
|
||||
// ignore
|
||||
}
|
||||
},
|
||||
STOP_TIMEOUT,
|
||||
async () => {
|
||||
throw new Error(`Proc "${name}" was stopped but never emiited either the "close" or "exit" events after ${STOP_TIMEOUT} ms`);
|
||||
throw new Error(`Proc "${name}" was stopped but never emiited either the "exit" or "error" event after ${STOP_TIMEOUT} ms`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -833,6 +833,16 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
|
|||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
cross-spawn@^6.0.0:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
dependencies:
|
||||
nice-try "^1.0.4"
|
||||
path-key "^2.0.1"
|
||||
semver "^5.5.0"
|
||||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
cryptiles@2.x.x:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
|
||||
|
@ -891,6 +901,18 @@ esutils@^2.0.2:
|
|||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
|
||||
|
||||
execa@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50"
|
||||
dependencies:
|
||||
cross-spawn "^6.0.0"
|
||||
get-stream "^3.0.0"
|
||||
is-stream "^1.1.0"
|
||||
npm-run-path "^2.0.0"
|
||||
p-finally "^1.0.0"
|
||||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
expand-brackets@^0.1.4:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
|
||||
|
@ -1006,6 +1028,10 @@ gauge@~2.7.3:
|
|||
strip-ansi "^3.0.1"
|
||||
wide-align "^1.1.0"
|
||||
|
||||
get-stream@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
||||
|
@ -1184,6 +1210,10 @@ is-primitive@^2.0.0:
|
|||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
|
||||
is-typedarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
|
@ -1192,6 +1222,10 @@ isarray@1.0.0, isarray@~1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
|
||||
isobject@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
|
||||
|
@ -1335,6 +1369,10 @@ nan@^2.3.0:
|
|||
version "2.9.2"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.9.2.tgz#f564d75f5f8f36a6d9456cca7a6c4fe488ab7866"
|
||||
|
||||
nice-try@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4"
|
||||
|
||||
node-pre-gyp@^0.6.39:
|
||||
version "0.6.39"
|
||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649"
|
||||
|
@ -1364,6 +1402,12 @@ normalize-path@^2.0.0, normalize-path@^2.0.1:
|
|||
dependencies:
|
||||
remove-trailing-separator "^1.0.1"
|
||||
|
||||
npm-run-path@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
|
||||
dependencies:
|
||||
path-key "^2.0.0"
|
||||
|
||||
npmlog@^4.0.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
|
||||
|
@ -1421,6 +1465,10 @@ output-file-sync@^1.1.2:
|
|||
mkdirp "^0.5.1"
|
||||
object-assign "^4.1.0"
|
||||
|
||||
p-finally@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
|
||||
|
||||
parse-glob@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
|
||||
|
@ -1434,6 +1482,10 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
|
||||
path-key@^2.0.0, path-key@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
|
||||
|
||||
performance-now@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
|
||||
|
@ -1594,7 +1646,7 @@ safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
|||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
|
||||
|
||||
semver@^5.3.0:
|
||||
semver@^5.3.0, semver@^5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
|
||||
|
@ -1606,6 +1658,16 @@ set-immediate-shim@^1.0.1:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
|
||||
|
||||
shebang-command@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
||||
dependencies:
|
||||
shebang-regex "^1.0.0"
|
||||
|
||||
shebang-regex@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
||||
|
||||
signal-exit@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
|
@ -1668,6 +1730,10 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1:
|
|||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
strip-eof@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
|
||||
|
||||
strip-json-comments@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||
|
@ -1717,9 +1783,9 @@ traverse@0.6.6:
|
|||
version "0.6.6"
|
||||
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
|
||||
|
||||
tree-kill@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.1.0.tgz#c963dcf03722892ec59cba569e940b71954d1729"
|
||||
tree-kill@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36"
|
||||
|
||||
trim-right@^1.0.1:
|
||||
version "1.0.1"
|
||||
|
@ -1765,6 +1831,12 @@ verror@1.10.0:
|
|||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
which@^1.2.9:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wide-align@^1.1.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue