Skip to content
This repository has been archived by the owner on May 15, 2019. It is now read-only.

Commit

Permalink
Refactor Supervisor to run each function as its own persistent worker. (
Browse files Browse the repository at this point in the history
#55)

Fixes #44
Fixes #46
Fixes #53
  • Loading branch information
jmdobry authored Mar 5, 2017
1 parent e60acaa commit 51fa8d9
Show file tree
Hide file tree
Showing 27 changed files with 786 additions and 671 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
##### 1.0.0-alpha.7 - 05 March 2017

###### Breaking changes
- #44 - Re-architect to process per function

###### Bug fixes
- #46 (again) - Inconsistent behaviour for parsing path and path params
- #53 - HTTP Function hangs when debugging

##### 1.0.0-alpha.6 - 28 February 2017

###### Bug fixes
Expand Down
22 changes: 22 additions & 0 deletions bin/functions
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,26 @@ if (!semver.satisfies(process.version, '>= 6.9.1')) {
process.exit(1);
}

const path = require('path');
const Configstore = require('configstore');
const pkg = require('../package.json');

const server = new Configstore(path.join(pkg.name, '/.active-server'));

if (server.get('started')) {
if (!server.get('stopped')) {
const emulatorVersion = server.get('version');
const cliVersion = pkg.version;

if (!semver.satisfies(emulatorVersion, `>= ${cliVersion}`)) {
console.error(`The version of the currently running Emulator ${emulatorVersion ? '(' + emulatorVersion + ')' : ''} is lower than that of the installed CLI (${cliVersion}). Please shutdown any running Emulator processes and restart using the installed CLI.`);
process.exit(1);
}
} else {
if (server.get('pid')) {
console.error(`Warning: You either have an orphaned Emulator process (PID: ${server.get('pid')}) or the previously running Emulator process was not shutdown properly, please verify.`);
}
}
}

require('../src/cli').main(process.argv.slice(2));
23 changes: 12 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@google-cloud/functions-emulator",
"description": "Google Cloud Functions Emulator",
"version": "1.0.0-alpha.6",
"version": "1.0.0-alpha.7",
"license": "Apache-2.0",
"author": "Google Inc.",
"engines": {
Expand Down Expand Up @@ -42,13 +42,13 @@
},
"scripts": {
"lint": "semistandard \"**/*.js\"",
"mocha": "mocha test/_setup test/ --recursive -t 30000 -S -R spec --require intelli-espower-loader",
"mocha": "mocha test/_setup test/ --recursive -t 60000 -S -R spec --require intelli-espower-loader",
"unit-test": "npm run mocha -- --grep \"unit/\"",
"system-test": "npm run mocha -- --grep \"system/\"",
"mocha-debug": "mocha debug test/_setup test/ --recursive -t 30000 -S -R spec --require intelli-espower-loader",
"cover": "nyc --cache mocha test/_setup test/ --recursive -t 30000 -S -R spec --require intelli-espower-loader && nyc report --reporter=html",
"unit-cover": "nyc --cache mocha test/_setup test/ --grep \"unit/\" --recursive -t 30000 -S -R spec --require intelli-espower-loader && nyc report --reporter=html",
"system-cover": "nyc --cache mocha test/_setup test/ --grep \"system/\" --recursive -t 30000 -S -R spec --require intelli-espower-loader && nyc report --reporter=html",
"mocha-debug": "mocha debug test/_setup test/ --recursive -t 60000 -S -R spec --require intelli-espower-loader",
"cover": "nyc --cache mocha test/_setup test/ --recursive -t 60000 -S -R spec --require intelli-espower-loader && nyc report --reporter=html",
"unit-cover": "nyc --cache mocha test/_setup test/ --grep \"unit/\" --recursive -t 60000 -S -R spec --require intelli-espower-loader && nyc report --reporter=html",
"system-cover": "nyc --cache mocha test/_setup test/ --grep \"system/\" --recursive -t 60000 -S -R spec --require intelli-espower-loader && nyc report --reporter=html",
"test": "npm run lint && npm run cover",
"format": "semistandard-format -w",
"start": "node .",
Expand All @@ -58,23 +58,24 @@
"@google-cloud/storage": "0.7.0",
"adm-zip": "0.4.7",
"ajv": "4.11.3",
"body-parser": "1.16.1",
"body-parser": "1.17.0",
"cli-table2": "0.2.0",
"colors": "1.1.2",
"configstore": "3.0.0",
"express": "4.14.1",
"google-proto-files": "0.9.1",
"googleapis": "16.1.0",
"express": "4.15.0",
"google-proto-files": "0.10.0",
"googleapis": "17.1.0",
"got": "6.7.1",
"grpc": "1.1.2",
"http-proxy": "^1.16.2",
"lodash": "4.17.4",
"semver": "5.3.0",
"serializerr": "1.0.3",
"supertest": "3.0.0",
"tmp": "0.0.31",
"uuid": "3.0.1",
"winston": "2.3.1",
"yargs": "6.6.0"
"yargs": "7.0.1"
},
"devDependencies": {
"intelli-espower-loader": "1.0.1",
Expand Down
24 changes: 1 addition & 23 deletions src/cli/commands/call.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ exports.desecription = DESCRIPTION;
exports.builder = (yargs) => {
yargs
.usage(USAGE)
.demand(1)
.options(_.merge({
data: {
description: `Specify inline the JSON data to send to the function. ${'Default:'.bold} ${'{}'.green}`,
Expand Down Expand Up @@ -81,28 +80,7 @@ exports.handler = (opts) => {
const controller = new Controller(opts);

return controller.doIfRunning()
.then(() => {
if (controller.server.get('inspect')) {
if (controller.server.get('isolation') === 'inprocess') {
console.log(`Function execution paused. Connect to the debugger on port ${controller.server.get('inspectPort')} (e.g. using the "node" launch type in VSCode).\n`);
} else {
controller.getDebuggingUrl().then((debugUrl) => {
let debugStr = `Function execution paused. Connect to the debugger on port ${controller.server.get('inspectPort')} (e.g. using the "node2" launch type in VSCode), or open the following URL in Chrome:`;
if (debugUrl) {
// If found, include it in the string that gets printed
debugStr += `\n\n ${debugUrl}\n`;
} else {
debugStr += `\n\nError: Could not find Chrome debugging URL in log file. Look for it yourself in ${controller.server.get('logFile')}.`;
}
console.log(debugStr);
});
}
} else if (controller.server.get('debug')) {
console.log(`Function execution paused. Connect to the debugger on port ${controller.server.get('debugPort')} (e.g. using the "node" launch type in VSCode).\n`);
}

return controller.call(opts.functionName, opts.data);
})
.then(() => controller.call(opts.functionName, opts.data))
.then(([body, response]) => {
controller.log(`ExecutionId: ${body.executionId}`);
if (body.result) {
Expand Down
7 changes: 0 additions & 7 deletions src/cli/commands/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ const EPILOGUE = `Available configuration options:
${'restPort'.bold}
${OPTIONS.restPort.description}
${'runSupervisor'.bold}
${OPTIONS.runSupervisor.description}
${'verbose'.bold}
${OPTIONS.verbose.description}
Expand All @@ -70,9 +67,6 @@ const EPILOGUE = `Available configuration options:
${'inspectPort'.bold}
${OPTIONS.inspectPort.description}
${'isolation'.bold}
${OPTIONS.isolation.description}
${'supervisorHost'.bold}
${OPTIONS.supervisorHost.description}
Expand Down Expand Up @@ -104,7 +98,6 @@ exports.description = DESCRIPTION;
exports.builder = (yargs) => {
yargs
.usage(USAGE)
.demand(1)
.command(require('./list'))
.command(require('./set'))
.command(require('./defaults'))
Expand Down
1 change: 0 additions & 1 deletion src/cli/commands/config/set.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ exports.description = DESCRIPTION;
exports.builder = (yargs) => {
yargs
.usage(USAGE)
.demand(2)
.epilogue(configCommand.helpMessage);

EXAMPLES['config.set'].forEach((e) => yargs.example(e[0], e[1]));
Expand Down
1 change: 0 additions & 1 deletion src/cli/commands/delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ exports.description = DESCRIPTION;
exports.builder = (yargs) => {
yargs
.usage(USAGE)
.demand(1)
.options(_.pick(OPTIONS, ['grpcHost', 'grpcPort', 'projectId', 'region', 'service', 'restHost', 'restPort']));

EXAMPLES['delete'].forEach((e) => yargs.example(e[0], e[1]));
Expand Down
1 change: 0 additions & 1 deletion src/cli/commands/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ exports.description = DESCRIPTION;
exports.builder = (yargs) => {
yargs
.usage(USAGE)
.demand(1)
.options(_.merge({
'entry-point': {
description: 'The name of the function exported in the source code that will be executed.',
Expand Down
1 change: 0 additions & 1 deletion src/cli/commands/describe.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ exports.description = DESCRIPTION;
exports.builder = (yargs) => {
yargs
.usage(USAGE)
.demand(1)
.options(_.pick(OPTIONS, ['grpcHost', 'grpcPort', 'projectId', 'region', 'service', 'restHost', 'restPort']));

EXAMPLES['describe'].forEach((e) => yargs.example(e[0], e[1]));
Expand Down
1 change: 0 additions & 1 deletion src/cli/commands/event-types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ exports.description = DESCRIPTION;
exports.builder = (yargs) => {
yargs
.usage(USAGE)
.demand(1)
.command(require('./list'));

EXAMPLES['event-types'].forEach((e) => yargs.example(e[0], e[1]));
Expand Down
1 change: 0 additions & 1 deletion src/cli/commands/logs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ exports.description = DESCRIPTION;
exports.builder = (yargs) => {
yargs
.usage(USAGE)
.demand(1)
.command(require('./read'))
.epilogue('For more information, see https://github.com/GoogleCloudPlatform/cloud-functions-emulator/wiki/Viewing-logs');

Expand Down
29 changes: 4 additions & 25 deletions src/cli/commands/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,11 @@ exports.options = [
'grpcPort',
'inspect',
'inspectPort',
'isolation',
'logFile',
'projectId',
'region',
'restHost',
'restPort',
'runSupervisor',
'service',
'storage',
'supervisorHost',
Expand Down Expand Up @@ -97,29 +95,10 @@ exports.handler = (opts) => {
controller.write(' STARTED\n'.green);
controller.log(`HTTP functions receiving requests at http://${config.supervisorHost}:${config.supervisorPort}/${config.projectId}/${config.region}/FUNCTION_NAME\n`);

// Only start the Emulator itself in debug or inspect mode if the
// isolation model is "inprocess"
if (config.isolation === 'inprocess') {
if (config.inspect) {
promise = controller.getDebuggingUrl().then((debugUrl) => {
let debugStr = `Started in inspect mode. Connect to the debugger on port ${config.inspectPort} (e.g. using the "node2" launch type in VSCode), or open the following URL in Chrome:`;
if (debugUrl) {
// If found, include it in the string that gets printed
debugStr += `\n\n ${debugUrl}\n`;
} else {
debugStr += `\n\nError: Could not find Chrome debugging URL in log file. Look for it yourself in ${config.logFile}.`;
}
console.log(`${debugStr}\n`);
});
} else if (config.debug) {
console.log(`Connect to the debugger on port ${config.debugPort} (e.g. using the "node" launch type in VSCode).\n`);
}
} else {
if (config.inspect) {
console.log(`Inspect mode is enabled for the Supervisor. During function execution the debugger will listen on port ${config.inspectPort} and the Chrome debugging URL will be printed to the console.\n`);
} else if (config.debug) {
console.log(`Debug mode is enabled for the Supervisor. During function execution the debugger will listen on port ${config.debugPort}.\n`);
}
if (config.inspect) {
console.log(`Inspect mode is enabled for the Supervisor. Check the logs for the workers' debugger ports.\n`);
} else if (config.debug) {
console.log(`Debug mode is enabled for the Supervisor. Check the logs for the workers' debugger ports.\n`);
}

return promise;
Expand Down
8 changes: 0 additions & 8 deletions src/cli/commands/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,6 @@ exports.handler = (opts) => {
}

table.push([{ colSpan: 2, content: 'Supervisor'.cyan }]);

if (config.runSupervisor) {
table.push(['Status'.white, 'RUNNING'.green]);
table.push(['Isolation Mode'.white, config.isolation]);
} else {
table.push(['Status'.white, 'DETACHED'.yellow]);
}

table.push(['Trigger URL'.white, `http://${config.supervisorHost}:${config.supervisorPort}/${config.projectId}/${config.region}/FUNCTION_NAME`]);
} else {
let time;
Expand Down
29 changes: 8 additions & 21 deletions src/cli/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -452,32 +452,20 @@ class Controller {
`--projectId=${this.config.projectId}`,
`--timeout=${this.config.timeout}`,
`--verbose=${this.config.verbose}`,
`--isolation=${this.config.isolation}`,
`--useMocks=${this.config.useMocks}`,
`--logFile=${this.config.logFile}`,
`--restHost=${this.config.restHost}`,
`--restPort=${this.config.restPort}`,
`--runSupervisor=${this.config.runSupervisor}`,
`--supervisorHost=${this.config.supervisorHost}`,
`--supervisorPort=${this.config.supervisorPort}`
];

// Only start the Emulator itself in debug or inspect mode if the
// isolation model is "inprocess"
if (this.config.isolation === 'inprocess') {
if (this.config.inspect) {
args.unshift(`--inspect=${this.config.inspectPort}`);
} else if (this.config.debug) {
args.unshift(`--debug=${this.config.debugPort}`);
}
} else {
if (this.config.inspect) {
args.push(`--inspect=${this.config.inspect}`);
args.push(`--inspectPort=${this.config.inspectPort}`);
} else if (this.config.debug) {
args.push(`--debug=${this.config.debug}`);
args.push(`--debugPort=${this.config.debugPort}`);
}
if (this.config.inspect) {
args.push(`--inspect=${this.config.inspect}`);
args.push(`--inspectPort=${this.config.inspectPort}`);
} else if (this.config.debug) {
args.push(`--debug=${this.config.debug}`);
args.push(`--debugPort=${this.config.debugPort}`);
}

// Make sure the child is detached, otherwise it will be bound to the
Expand All @@ -498,19 +486,18 @@ class Controller {
grpcPort: this.config.grpcPort,
inspect: this.config.inspect,
inspectPort: this.config.inspectPort,
isolation: this.config.isolation,
logFile: this.config.logFile,
projectId: this.config.projectId,
region: this.config.region,
restHost: this.config.restHost,
restPort: this.config.restPort,
runSupervisor: this.config.runSupervisor,
started: Date.now(),
storage: this.config.storage,
supervisorHost: this.config.supervisorHost,
supervisorPort: this.config.supervisorPort,
useMocks: this.config.useMocks,
verbose: this.config.verbose
verbose: this.config.verbose,
version: pkg.version
});
this.server.delete('stopped');

Expand Down
2 changes: 1 addition & 1 deletion src/client/grpc-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class GrpcClient extends Client {
this.functionsClient.listFunctions({
pageSize: 1,
location: 'heartbeat'
}, (err, response) => {
}, { deadline }, (err, response) => {
if (err) {
reject(this._processError(err));
} else {
Expand Down
4 changes: 1 addition & 3 deletions src/defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@
"grpcPort": 8009,
"inspect": false,
"inspectPort": 9229,
"isolation": "childprocess",
"logFile": "logs/cloud-functions-emulator.log",
"region": "us-central1",
"restHost": "localhost",
"restPort": 8008,
"runSupervisor": true,
"service": "rest",
"storage": "configstore",
"supervisorHost": "localhost",
"supervisorPort": 8010,
"timeout": 30000,
"timeout": 60000,
"useMocks": false,
"verbose": false
}
Loading

2 comments on commit 51fa8d9

@jmdobry
Copy link
Contributor Author

@jmdobry jmdobry commented on 51fa8d9 Mar 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes #35

@jmdobry
Copy link
Contributor Author

@jmdobry jmdobry commented on 51fa8d9 Mar 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes #17

Please sign in to comment.