performance: keep action code in memory and use that on restore
instead of reading it again from the backup action with another slow request
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 @@
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 @@
// 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 @@
// 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 @@
// create copy
await this.wsk.actions.update({
name: backupName,
- action: action
+ action: agentAction
});
debug(`created action backup ${backupName}`);
@@ -207,21 +225,21 @@
}
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 @@
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 { 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 @@
// 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 @@
}]);
// shutdown/restore process
- test.mockReadBackupAction(action, code);
test.mockRestoreAction(action, code);
test.mockRemoveBackupAction(action);
test.openwhiskNock()
@@ -234,7 +233,6 @@
);
// 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 @@
.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 @@
mockInstallAgent(name);
// shutdown/restore process
- mockReadBackupAction(name, code, binary);
mockRestoreAction(name, code, binary);
mockRemoveBackupAction(name);
}