This is an automated email from the ASF dual-hosted git repository. alexkli pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/openwhisk-wskdebug.git
commit 560f81d0ad70e1969bdc09c2bf0faec8ae37c243 Author: Alexander Klimetschek <[email protected]> AuthorDate: Mon Apr 13 18:01:53 2020 -0700 performance: keep action code in memory and use that on restore instead of reading it again from the backup action with another slow request --- package-lock.json | 3 +-- package.json | 2 +- src/agentmgr.js | 54 ++++++++++++++++++++++++++++++++++++++------------- src/debugger.js | 5 +---- test/agentmgr.test.js | 2 -- test/ngrok.test.js | 3 +-- test/test.js | 1 - 7 files changed, 45 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 00a4067..ce21bad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -583,8 +583,7 @@ "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" }, "codecov": { "version": "3.6.5", diff --git a/package.json b/package.json index b717ddf..27004d0 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "file": "test/logfile.setup.js" }, "dependencies": { + "clone": "^2.1.2", "debug": "^4.1.1", "fetch-retry": "^3.1.0", "fs-extra": "^8.1.0", @@ -58,7 +59,6 @@ }, "devDependencies": { "chmodr": "^1.2.0", - "clone": "^2.1.2", "codecov": "^3.6.5", "eslint": "^6.8.0", "eslint-config-problems": "^4.0.0", diff --git a/src/agentmgr.js b/src/agentmgr.js index 1806c05..d862e05 100644 --- a/src/agentmgr.js +++ b/src/agentmgr.js @@ -28,6 +28,8 @@ try { const fs = require('fs-extra'); const sleep = require('util').promisify(setTimeout); const debug = require('./debug'); +const prettyBytes = require('pretty-bytes'); +const clone = require('clone'); function getAnnotation(action, key) { const a = action.annotations.find(a => a.key === key); @@ -152,17 +154,33 @@ class AgentMgr { // user can switch between agents (ngrok or not), hence we need to restore first // (better would be to track the agent + its version and avoid a restore, but that's TBD) if (this.agentInstalled) { - return this.restoreAction(); + this.actionWithCode = await this.restoreAction(); + } else { + this.actionWithCode = await this.wsk.actions.get(this.actionName); + debug(`fetched action code from openwhisk (${prettyBytes(this.actionWithCode.exec.code.length)})`); + + } + // extra sanity check + if (isAgent(this.actionWithCode)) { + throw new Error("Action seems to be a left over wskdebug agent instead of the original action. Possible bug in wskdebug. Please redeploy your action. Aborting."); } - return this.wsk.actions.get(this.actionName); + return this.actionWithCode; } - async installAgent(action, invoker) { + async installAgent(invoker) { this.agentInstalled = true; let agentName; + // base agent on the original action to keep default parameters & annotations + const agentAction = this.actionWithCode ? clone(this.actionWithCode) : { + exec: {}, + limits: {}, + annotations: [], + parameters: [] + }; + // choose the right agent implementation let agentCode; if (this.argv.ngrok) { @@ -171,7 +189,7 @@ class AgentMgr { // agent using ngrok for forwarding agentName = "ngrok"; - agentCode = await this.ngrokAgent.getAgent(action); + agentCode = await this.ngrokAgent.getAgent(agentAction); debug("started local ngrok proxy"); } else { @@ -198,7 +216,7 @@ class AgentMgr { // create copy await this.wsk.actions.update({ name: backupName, - action: action + action: agentAction }); debug(`created action backup ${backupName}`); @@ -207,21 +225,21 @@ class AgentMgr { } if (this.argv.condition) { - action.parameters.push({ + agentAction.parameters.push({ key: "$condition", value: this.argv.condition }); } try { - await this.pushAgent(action, agentCode, backupName); + await this.pushAgent(agentAction, agentCode, backupName); } catch (e) { // openwhisk does not support concurrent nodejs actions, try with another if (e.statusCode === 400 && e.error && typeof e.error.error === "string" && e.error.error.includes("concurrency")) { console.log(`The Openwhisk server does not support concurrent actions, using alternative agent. Consider using --ngrok for a possibly faster agent.`); this.concurrency = false; agentCode = await this.getPollingActivationDbAgent(); - await this.pushAgent(action, agentCode, backupName); + await this.pushAgent(agentAction, agentCode, backupName); } } debug(`installed agent (${agentName}) in place of ${this.actionName}`); @@ -408,20 +426,30 @@ class AgentMgr { const copy = getActionCopyName(this.actionName); try { - // the original was backed up in the copy - const original = await this.wsk.actions.get(copy); - debug("restore: fetched action original from backup copy (move step 1)"); + // unfortunately, openwhisk does not support a server-side "move action" API, + // otherwise the next 3 steps (read, update, delete) could be a single + // and presumably fast move operation + + let original; + if (this.actionWithCode) { + // normal case during shutdown: we have the original action in memory + original = this.actionWithCode; + } else { + // the original was fetched before or was backed up in the copy + original = await this.wsk.actions.get(copy) + debug("restore: fetched action original from backup copy"); + } // copy the backup (copy) to the regular action await this.wsk.actions.update({ name: this.actionName, action: original }); - debug("restore: restored action with original (move step 2)"); + debug("restore: restored original action"); // remove the backup await this.wsk.actions.delete(copy); - debug("restore: deleted backup copy (move step 3)"); + debug("restore: deleted backup copy"); // remove any helpers if they exist await deleteActionIfExists(this.wsk, `${this.actionName}_wskdebug_invoked`); diff --git a/src/debugger.js b/src/debugger.js index db33974..91d8d79 100644 --- a/src/debugger.js +++ b/src/debugger.js @@ -25,7 +25,6 @@ const openwhisk = require('openwhisk'); const { spawnSync } = require('child_process'); const sleep = require('util').promisify(setTimeout); const debug = require('./debug'); -const prettyBytes = require('pretty-bytes'); const prettyMilliseconds = require('pretty-ms'); /** @@ -89,14 +88,12 @@ class Debugger { // get code and /init local container const actionWithCode = await this.agentMgr.readActionWithCode(); - debug(`fetched action code from openwhisk (${prettyBytes(actionWithCode.exec.code.length)})`); - await this.invoker.init(actionWithCode); debug("installed action on container (/init)"); // setup agent in openwhisk - await this.agentMgr.installAgent(actionWithCode, this.invoker); + await this.agentMgr.installAgent(this.invoker); if (this.argv.onStart) { console.log("On start:", this.argv.onStart); diff --git a/test/agentmgr.test.js b/test/agentmgr.test.js index d9163c9..b7fae8d 100644 --- a/test/agentmgr.test.js +++ b/test/agentmgr.test.js @@ -122,7 +122,6 @@ describe('agentmgr', function() { }]); // shutdown/restore process - test.mockReadBackupAction(action, code); test.mockRestoreAction(action, code); test.mockRemoveBackupAction(action); test.openwhiskNock() @@ -234,7 +233,6 @@ describe('agentmgr', function() { ); // 6. restore - test.mockReadBackupAction(action, actionCode); test.mockRestoreAction(action, actionCode); test.mockRemoveBackupAction(action); diff --git a/test/ngrok.test.js b/test/ngrok.test.js index a095659..b9485e6 100644 --- a/test/ngrok.test.js +++ b/test/ngrok.test.js @@ -155,8 +155,7 @@ describe('ngrok', function() { .matchHeader("authorization", test.openwhiskApiAuthHeader()) .reply(200, test.nodejsActionDescription(actionName)); - test.mockReadBackupAction(actionName); - test.mockRestoreAction(actionName); + test.mockRestoreAction(actionName, code); test.mockRemoveBackupAction(actionName); // wskdebug myaction action.js --ngrok -p ${test.port} diff --git a/test/test.js b/test/test.js index d39c539..d59e77e 100644 --- a/test/test.js +++ b/test/test.js @@ -191,7 +191,6 @@ function expectAgent(name, code, binary=false) { mockInstallAgent(name); // shutdown/restore process - mockReadBackupAction(name, code, binary); mockRestoreAction(name, code, binary); mockRemoveBackupAction(name); }
