From 761b9f8a15d2367af6e34d68aac73b152d38cddf Mon Sep 17 00:00:00 2001 From: Daniel Imhoff Date: Thu, 2 Aug 2018 10:11:43 -0500 Subject: [PATCH 1/4] use tree-kill to kill leftover processes --- packages/@ionic/cli-framework/package.json | 1 + packages/@ionic/cli-framework/src/utils/process.ts | 13 +++++++++++++ packages/@ionic/cli-utils/src/lib/serve.ts | 4 ++-- packages/@ionic/cli-utils/src/lib/shell.ts | 4 ++-- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/@ionic/cli-framework/package.json b/packages/@ionic/cli-framework/package.json index 0deebb3214..3cbb31df9d 100644 --- a/packages/@ionic/cli-framework/package.json +++ b/packages/@ionic/cli-framework/package.json @@ -56,6 +56,7 @@ "stream-combiner2": "^1.1.1", "string-width": "^2.1.1", "strip-ansi": "^4.0.0", + "tree-kill": "^1.2.0", "tslib": "^1.9.0", "untildify": "^3.0.2", "wrap-ansi": "^3.0.1", diff --git a/packages/@ionic/cli-framework/src/utils/process.ts b/packages/@ionic/cli-framework/src/utils/process.ts index f8e0a07f3a..17bcea2241 100644 --- a/packages/@ionic/cli-framework/src/utils/process.ts +++ b/packages/@ionic/cli-framework/src/utils/process.ts @@ -1,5 +1,6 @@ import * as Debug from 'debug'; import * as lodash from 'lodash'; +import * as kill from 'tree-kill'; import { createCaseInsensitiveObject } from './object'; @@ -7,6 +8,18 @@ const debug = Debug('ionic:cli-framework:utils:process'); export const ERROR_TIMEOUT_REACHED = 'TIMEOUT_REACHED'; +export function killProcessTree(pid: number, signal: string | number = 'SIGTERM'): Promise { + return new Promise((resolve, reject) => { + kill(pid, signal, err => { + if (err) { + return reject(err); + } + + resolve(); + }); + }); +} + /** * Creates an alternative implementation of `process.env` object. * diff --git a/packages/@ionic/cli-utils/src/lib/serve.ts b/packages/@ionic/cli-utils/src/lib/serve.ts index f1bd165022..8c7786924b 100644 --- a/packages/@ionic/cli-utils/src/lib/serve.ts +++ b/packages/@ionic/cli-utils/src/lib/serve.ts @@ -1,7 +1,7 @@ import { BaseError, LOGGER_LEVELS, NetworkInterface, OptionGroup, PromptModule, createPrefixedFormatter } from '@ionic/cli-framework'; import { fsReadJsonFile } from '@ionic/cli-framework/utils/fs'; import { findClosestOpenPort, getExternalIPv4Interfaces, isHostConnectable } from '@ionic/cli-framework/utils/network'; -import { onBeforeExit, processExit } from '@ionic/cli-framework/utils/process'; +import { killProcessTree, onBeforeExit, processExit } from '@ionic/cli-framework/utils/process'; import { str2num } from '@ionic/cli-framework/utils/string'; import chalk from 'chalk'; import * as Debug from 'debug'; @@ -529,7 +529,7 @@ export abstract class ServeCLI extends EventEmitter { p.on('error', errorHandler); p.on('close', closeHandler); - onBeforeExit(async () => p.kill()); + onBeforeExit(async () => killProcessTree(p.pid)); const log = this.e.log.clone(); log.setFormatter(createPrefixedFormatter(chalk.dim(`[${this.resolvedProgram === this.program ? this.prefix : this.resolvedProgram}]`))); diff --git a/packages/@ionic/cli-utils/src/lib/shell.ts b/packages/@ionic/cli-utils/src/lib/shell.ts index c3e5b25fe4..5ce0cefcb6 100644 --- a/packages/@ionic/cli-utils/src/lib/shell.ts +++ b/packages/@ionic/cli-utils/src/lib/shell.ts @@ -1,5 +1,5 @@ import { ERROR_SHELL_COMMAND_NOT_FOUND, LOGGER_LEVELS, ShellCommandError } from '@ionic/cli-framework'; -import { createProcessEnv, onBeforeExit } from '@ionic/cli-framework/utils/process'; +import { createProcessEnv, killProcessTree, onBeforeExit } from '@ionic/cli-framework/utils/process'; import { ShellCommand } from '@ionic/cli-framework/utils/shell'; import { combineStreams } from '@ionic/cli-framework/utils/streams'; import chalk from 'chalk'; @@ -69,7 +69,7 @@ export class Shell implements IShell { } if (killOnExit) { - onBeforeExit(async () => promise.p.kill()); + onBeforeExit(async () => killProcessTree(promise.p.pid)); } await promise; From 931a6a90c274f87a5f956c625f266f8b7d07e08b Mon Sep 17 00:00:00 2001 From: Daniel Imhoff Date: Thu, 2 Aug 2018 10:16:59 -0500 Subject: [PATCH 2/4] add debug statement for error --- packages/@ionic/cli-framework/src/utils/process.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/@ionic/cli-framework/src/utils/process.ts b/packages/@ionic/cli-framework/src/utils/process.ts index 17bcea2241..f3da7bfaa9 100644 --- a/packages/@ionic/cli-framework/src/utils/process.ts +++ b/packages/@ionic/cli-framework/src/utils/process.ts @@ -12,6 +12,7 @@ export function killProcessTree(pid: number, signal: string | number = 'SIGTERM' return new Promise((resolve, reject) => { kill(pid, signal, err => { if (err) { + debug('error while killing process tree for %d: %o', pid, err); return reject(err); } From 717f92735ba75a0ed1a2323eb7dd33bcc8c31a64 Mon Sep 17 00:00:00 2001 From: Daniel Imhoff Date: Fri, 3 Aug 2018 14:01:44 -0500 Subject: [PATCH 3/4] lock-in tree-kill --- packages/@ionic/cli-framework/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@ionic/cli-framework/package.json b/packages/@ionic/cli-framework/package.json index 3cbb31df9d..eca6fcb7f2 100644 --- a/packages/@ionic/cli-framework/package.json +++ b/packages/@ionic/cli-framework/package.json @@ -56,7 +56,7 @@ "stream-combiner2": "^1.1.1", "string-width": "^2.1.1", "strip-ansi": "^4.0.0", - "tree-kill": "^1.2.0", + "tree-kill": "1.2.0", "tslib": "^1.9.0", "untildify": "^3.0.2", "wrap-ansi": "^3.0.1", From aeb1b1956d52b23c2c99a56ea2ad9264295d4c82 Mon Sep 17 00:00:00 2001 From: Daniel Imhoff Date: Mon, 6 Aug 2018 14:24:49 -0500 Subject: [PATCH 4/4] close environment this will close the readline and relinquish stdin/stdout --- packages/ionic/src/commands/cordova/run.ts | 1 + packages/ionic/src/commands/serve.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/ionic/src/commands/cordova/run.ts b/packages/ionic/src/commands/cordova/run.ts index 5448a59759..16123d2045 100644 --- a/packages/ionic/src/commands/cordova/run.ts +++ b/packages/ionic/src/commands/cordova/run.ts @@ -206,6 +206,7 @@ ${chalk.cyan('[1]')}: ${chalk.bold('https://ionicframework.com/docs/developer-re const ws = log.createWriteStream(LOGGER_LEVELS.INFO); await this.runCordova(filterArgumentsForCordova(metadata, options), { stream: ws }); + this.env.close(); // TODO: better way await sleepForever(); } else { if (options.build) { diff --git a/packages/ionic/src/commands/serve.ts b/packages/ionic/src/commands/serve.ts index 5105c93777..d88d580e4a 100644 --- a/packages/ionic/src/commands/serve.ts +++ b/packages/ionic/src/commands/serve.ts @@ -143,6 +143,7 @@ Try the ${chalk.green('--lab')} option to see multiple platforms at once.`; // TODO: use runner directly await serve({ config: this.env.config, log: this.env.log, prompt: this.env.prompt, shell: this.env.shell, project: this.project }, inputs, options); + this.env.close(); // TODO: better way await sleepForever(); } }