Skip to content

Commit

Permalink
[cluster] ensure that main and worker processes exit
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Kosiakov <[email protected]>
  • Loading branch information
akosyakov committed Dec 4, 2017
1 parent 174f633 commit cd3a613
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ export class ApplicationPackageManager {

async startBrowser(args: string[]): Promise<void> {
const options: cp.ForkOptions = {
stdio: [0, 'pipe', 'pipe', 'ipc']
stdio: [0, 'pipe', 'pipe', 'ipc'],
env: {
...process.env,
THEIA_PARENT_PID: String(process.pid)
}
};
const debug = Number(process.env['THEIA_DEBUG']);
if (typeof debug === 'number' && !isNaN(debug)) {
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/node/cluster/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
// tslint:disable:no-console
import * as http from 'http';
import * as cluster from 'cluster';
import { checkParentAlive } from '../messaging/ipc-protocol';
import { MasterProcess } from './master-process';

checkParentAlive();

process.on('unhandledRejection', (reason, promise) => {
throw reason;
});
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/node/cluster/server-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// tslint:disable:no-console

import * as cluster from 'cluster';
import { createIpcEnv } from '../messaging/ipc-protocol';
import { RemoteServer, createRemoteServer } from './cluster-protocol';

export class ServerWorker {
Expand All @@ -26,7 +27,9 @@ export class ServerWorker {
this.initialized = new Promise<void>(resolve => onDidInitialize = resolve);

console.log('Starting server worker...');
this.worker = cluster.fork();
this.worker = cluster.fork(createIpcEnv({
env: process.env
}));
this.server = createRemoteServer(this.worker, { onDidInitialize, restart });

this.online = new Promise(resolve => this.worker.once('online', resolve));
Expand Down
23 changes: 3 additions & 20 deletions packages/core/src/node/messaging/ipc-bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,9 @@
import 'reflect-metadata';
import { ConsoleLogger } from 'vscode-ws-jsonrpc/lib/logger';
import { createMessageConnection, IPCMessageReader, IPCMessageWriter, Trace } from 'vscode-jsonrpc';
import { THEIA_PARENT_PID, THEIA_ENTRY_POINT, IPCEntryPoint } from './ipc-protocol';
import { checkParentAlive, ipcEntryPoint, IPCEntryPoint } from './ipc-protocol';

/**
* Exit the current process if the parent process is not alive.
* Relevant only for some OS, like Windows
*/
if (process.env[THEIA_PARENT_PID]) {
const parentPid = Number(process.env[THEIA_PARENT_PID]);

if (typeof parentPid === 'number' && !isNaN(parentPid)) {
setInterval(function () {
try {
// throws an exception if the main process doesn't exist anymore.
process.kill(parentPid, 0);
} catch (e) {
process.exit();
}
}, 5000);
}
}
checkParentAlive();

const reader = new IPCMessageReader(process);
const writer = new IPCMessageWriter(process);
Expand All @@ -37,5 +20,5 @@ connection.trace(Trace.Off, {
log: (message, data) => console.log(`${message} ${data}`)
});

const entryPoint = require(process.env[THEIA_ENTRY_POINT]!).default as IPCEntryPoint;
const entryPoint = require(ipcEntryPoint!).default as IPCEntryPoint;
entryPoint(connection);
11 changes: 5 additions & 6 deletions packages/core/src/node/messaging/ipc-connection-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as cp from "child_process";
import { injectable, inject } from "inversify";
import { Trace, IPCMessageReader, IPCMessageWriter, createMessageConnection, MessageConnection, Message } from "vscode-jsonrpc";
import { ILogger, ConnectionErrorHandler, DisposableCollection, Disposable } from "../../common";
import { THEIA_PARENT_PID, THEIA_ENTRY_POINT } from './ipc-protocol';
import { createIpcEnv } from './ipc-protocol';

export interface ResolvedIPCConnectionOptions {
readonly serverName: string
Expand Down Expand Up @@ -84,13 +84,12 @@ export class IPCConnectionProvider {
protected fork(options: ResolvedIPCConnectionOptions): cp.ChildProcess {
const forkOptions: cp.ForkOptions = {
silent: true,
env: {
...process.env
},
env: createIpcEnv({
env: process.env,
entryPoint: options.entryPoint
}),
execArgv: []
};
forkOptions.env[THEIA_PARENT_PID] = String(process.pid);
forkOptions.env[THEIA_ENTRY_POINT] = options.entryPoint;
if (typeof options.debug === 'number' && !isNaN(options.debug)) {
forkOptions.execArgv = ['--nolazy', '--inspect=' + options.debug];
}
Expand Down
38 changes: 36 additions & 2 deletions packages/core/src/node/messaging/ipc-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,41 @@

import { MessageConnection } from "vscode-jsonrpc";

export const THEIA_PARENT_PID = 'THEIA_PARENT_PID';
export const THEIA_ENTRY_POINT = 'THEIA_ENTRY_POINT';
const THEIA_PARENT_PID = 'THEIA_PARENT_PID';
const THEIA_ENTRY_POINT = 'THEIA_ENTRY_POINT';

export type IPCEntryPoint = (connection: MessageConnection) => void;

/**
* Exit the current process if the parent process is not alive.
* Relevant only for some OS, like Windows
*/
export function checkParentAlive(): void {
if (process.env[THEIA_PARENT_PID]) {
const parentPid = Number(process.env[THEIA_PARENT_PID]);

if (typeof parentPid === 'number' && !isNaN(parentPid)) {
setInterval(() => {
try {
// throws an exception if the main process doesn't exist anymore.
process.kill(parentPid, 0);
} catch {
process.exit();
}
}, 5000);
}
}
}

export const ipcEntryPoint = process.env[THEIA_ENTRY_POINT];

export function createIpcEnv(options?: {
entryPoint?: string
env?: NodeJS.ProcessEnv
}): NodeJS.ProcessEnv {
const op = Object.assign({}, options);
const childEnv = Object.assign({}, op.env);
childEnv[THEIA_PARENT_PID] = String(process.pid);
childEnv[THEIA_ENTRY_POINT] = op.entryPoint;
return childEnv;
}

0 comments on commit cd3a613

Please sign in to comment.