You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by al...@apache.org on 2020/04/14 07:53:33 UTC

[openwhisk-wskdebug] 03/09: performance: keep action code in memory and use that on restore

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 <ak...@adobe.com>
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);
 }