Skip to content

Commit 38217bf

Browse files
authored
fix(serve): properly cleanup child processes (#3481)
* use tree-kill to kill leftover processes * close environment this will close the readline and relinquish stdin/stdout
1 parent 12c3f35 commit 38217bf

File tree

6 files changed

+21
-4
lines changed

6 files changed

+21
-4
lines changed

packages/@ionic/cli-framework/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"stream-combiner2": "^1.1.1",
5757
"string-width": "^2.1.1",
5858
"strip-ansi": "^4.0.0",
59+
"tree-kill": "1.2.0",
5960
"tslib": "^1.9.0",
6061
"untildify": "^3.0.2",
6162
"wrap-ansi": "^3.0.1",

packages/@ionic/cli-framework/src/utils/process.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
import * as Debug from 'debug';
22
import * as lodash from 'lodash';
3+
import * as kill from 'tree-kill';
34

45
import { createCaseInsensitiveObject } from './object';
56

67
const debug = Debug('ionic:cli-framework:utils:process');
78

89
export const ERROR_TIMEOUT_REACHED = 'TIMEOUT_REACHED';
910

11+
export function killProcessTree(pid: number, signal: string | number = 'SIGTERM'): Promise<void> {
12+
return new Promise((resolve, reject) => {
13+
kill(pid, signal, err => {
14+
if (err) {
15+
debug('error while killing process tree for %d: %o', pid, err);
16+
return reject(err);
17+
}
18+
19+
resolve();
20+
});
21+
});
22+
}
23+
1024
/**
1125
* Creates an alternative implementation of `process.env` object.
1226
*

packages/@ionic/cli-utils/src/lib/serve.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BaseError, LOGGER_LEVELS, NetworkInterface, OptionGroup, PromptModule, createPrefixedFormatter } from '@ionic/cli-framework';
22
import { fsReadJsonFile } from '@ionic/cli-framework/utils/fs';
33
import { findClosestOpenPort, getExternalIPv4Interfaces, isHostConnectable } from '@ionic/cli-framework/utils/network';
4-
import { onBeforeExit, processExit } from '@ionic/cli-framework/utils/process';
4+
import { killProcessTree, onBeforeExit, processExit } from '@ionic/cli-framework/utils/process';
55
import { str2num } from '@ionic/cli-framework/utils/string';
66
import chalk from 'chalk';
77
import * as Debug from 'debug';
@@ -529,7 +529,7 @@ export abstract class ServeCLI<T extends ServeCLIOptions> extends EventEmitter {
529529
p.on('error', errorHandler);
530530
p.on('close', closeHandler);
531531

532-
onBeforeExit(async () => p.kill());
532+
onBeforeExit(async () => killProcessTree(p.pid));
533533

534534
const log = this.e.log.clone();
535535
log.setFormatter(createPrefixedFormatter(chalk.dim(`[${this.resolvedProgram === this.program ? this.prefix : this.resolvedProgram}]`)));

packages/@ionic/cli-utils/src/lib/shell.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ERROR_SHELL_COMMAND_NOT_FOUND, LOGGER_LEVELS, ShellCommandError } from '@ionic/cli-framework';
2-
import { createProcessEnv, onBeforeExit } from '@ionic/cli-framework/utils/process';
2+
import { createProcessEnv, killProcessTree, onBeforeExit } from '@ionic/cli-framework/utils/process';
33
import { ShellCommand } from '@ionic/cli-framework/utils/shell';
44
import { combineStreams } from '@ionic/cli-framework/utils/streams';
55
import chalk from 'chalk';
@@ -69,7 +69,7 @@ export class Shell implements IShell {
6969
}
7070

7171
if (killOnExit) {
72-
onBeforeExit(async () => promise.p.kill());
72+
onBeforeExit(async () => killProcessTree(promise.p.pid));
7373
}
7474

7575
await promise;

packages/ionic/src/commands/cordova/run.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ ${chalk.cyan('[1]')}: ${chalk.bold('https://ionicframework.com/docs/developer-re
206206
const ws = log.createWriteStream(LOGGER_LEVELS.INFO);
207207

208208
await this.runCordova(filterArgumentsForCordova(metadata, options), { stream: ws });
209+
this.env.close(); // TODO: better way
209210
await sleepForever();
210211
} else {
211212
if (options.build) {

packages/ionic/src/commands/serve.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ Try the ${chalk.green('--lab')} option to see multiple platforms at once.`;
143143

144144
// TODO: use runner directly
145145
await serve({ config: this.env.config, log: this.env.log, prompt: this.env.prompt, shell: this.env.shell, project: this.project }, inputs, options);
146+
this.env.close(); // TODO: better way
146147
await sleepForever();
147148
}
148149
}

0 commit comments

Comments
 (0)