Skip to content

Commit 5a29272

Browse files
committed
feat (invoke-action) handle SHUTDOWN tasks
- stop CodeRunner when SHUTDOWN task received (BKNDLSS-12038) - refactor task name (rename InvokeMethodTask to InvokeHandlerTask) - refactor invoke-action executor (get rid of switch)
1 parent 8293346 commit 5a29272

File tree

6 files changed

+129
-60
lines changed

6 files changed

+129
-60
lines changed

lib/server-code/runners/debug.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ const logger = require('../../util/logger'),
77
denodeify = require('../../util/promise').denodeify,
88
ServerCodeService = require('../services/server-code'),
99
tasksExecutor = require('./tasks/executor'),
10-
ServerCodeModel = require('../model'),
11-
Backendless = require('backendless');
10+
ServerCodeModel = require('../model');
1211

1312
const TASKS_AWAIT_TIMEOUT = 10;
1413
const SESSION_TTL = 60;

lib/server-code/runners/tasks/executor.js

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
'use strict';
22

3-
const wrapper = require('./util/result-wrapper'),
4-
Backendless = require('backendless');
3+
const wrapper = require('./util/result-wrapper');
4+
const Backendless = require('backendless');
55

6-
const executors = {
7-
['com.backendless.coderunner.commons.protocol.RequestMethodInvocation']: './invoke-method',
8-
['com.backendless.coderunner.commons.protocol.RequestActionInvocation']: './invoke-action',
9-
['com.backendless.coderunner.commons.protocol.RequestServiceInvocation']: './invoke-service'
10-
};
6+
const SHUTDOWN_CODE = 32768;
7+
const SHUTDOWN_ACTION = 'SHUTDOWN';
118

129
/**
1310
* @typedef {Object} InitAppData
@@ -28,49 +25,74 @@ const executors = {
2825

2926
const executor = module.exports = {};
3027

28+
executor.RMI = 'com.backendless.coderunner.commons.protocol.RequestMethodInvocation';
29+
executor.RAI = 'com.backendless.coderunner.commons.protocol.RequestActionInvocation';
30+
executor.RSI = 'com.backendless.coderunner.commons.protocol.RequestServiceInvocation';
31+
32+
const executors = {
33+
[executor.RMI]: './invoke-handler',
34+
[executor.RAI]: './invoke-action',
35+
[executor.RSI]: './invoke-service'
36+
};
37+
3138
/**
3239
* @param {?Error|ExceptionWrapper|String} err
3340
* @param {*} result
3441
* @returns {String}
3542
*/
3643
function invocationResult(err, result) {
37-
return JSON.stringify(wrapper.invocationResult(err, result));
44+
return JSON.stringify(wrapper.invocationResult(err, result));
3845
}
3946

4047
/**
4148
* @param {CodeRunnerTask} task
4249
* @returns {Function} task executor
4350
*/
4451
function getTaskExecutor(task) {
45-
const taskClass = task.___jsonclass;
52+
const taskClass = task.___jsonclass;
4653

47-
if (!executors[taskClass]) {
48-
throw new Error(`Unknown task [${taskClass}]`);
49-
}
54+
if (!executors[taskClass]) {
55+
throw new Error(`Unknown task [${taskClass}]`);
56+
}
5057

51-
return require(executors[taskClass]);
58+
return require(executors[taskClass]);
5259
}
5360

5461
/**
5562
* @param {CodeRunnerTask} task
5663
*/
5764
function initClientSdk(task) {
65+
if (task.initAppData) {
5866
Backendless.serverURL = task.initAppData.url;
5967
Backendless.initApp(task.applicationId, task.initAppData.secretKey, task.initAppData.appVersionName);
68+
}
69+
}
70+
71+
/**
72+
* A temporal workaround for http://bugs.backendless.com/browse/BKNDLSS-12041
73+
*
74+
* @param {CodeRunnerTask} task
75+
*/
76+
function fixTask(task) {
77+
if (task.___jsonclass === executor.RMI && task.eventId === SHUTDOWN_CODE) {
78+
task.___jsonclass = executor.RAI;
79+
task.actionType = SHUTDOWN_ACTION;
80+
}
6081
}
6182

6283
/**
6384
* @param {CodeRunnerTask} task
6485
* @param {Object} runnerOpts
65-
* @param {?ServerCodeModel} model
86+
* @param {ServerCodeModel=} model
6687
* @returns {Promise.<string>} InvocationResult JSON string
6788
*/
68-
executor.execute = function (task, runnerOpts, model) {
89+
executor.execute = function(task, runnerOpts, model) {
90+
return Promise.resolve()
91+
.then(() => initClientSdk(task))
92+
.then(() => fixTask(task))
93+
.then(() => getTaskExecutor(task))
94+
.then((taskExecutor) => taskExecutor(task, runnerOpts, model))
95+
.then(result => result && invocationResult(null, result))
96+
.catch(invocationResult);
97+
};
6998

70-
return Promise.resolve()
71-
.then(() => initClientSdk(task))
72-
.then(() => getTaskExecutor(task))
73-
.then((taskExecutor) => taskExecutor(task, runnerOpts, model))
74-
.then(result => result && invocationResult(null, result))
75-
.catch(invocationResult);
76-
};

lib/server-code/runners/tasks/invoke-action.js

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,6 @@ const logger = require('../../../util/logger'),
55
ServerCodeModel = require('../../model'),
66
path = require('path');
77

8-
const PARSE_SERVICE = 'PARSE_CUSTOM_SERVICE_FROM_JAR';
9-
const VALIDATE_SERVER_CODE = 'VALIDATE_SERVER_CODE';
10-
11-
/**
12-
* @typedef {CodeRunnerTask} InvokeActionTask
13-
* @property {String} actionType
14-
* @property {Object} argObject
15-
*/
16-
17-
/**
18-
* @param {InvokeActionTask} task
19-
* @param {Object} runnerOpts
20-
* @returns {*} Task Execution Result
21-
*/
22-
module.exports = function(task, runnerOpts) { //
23-
switch (task.actionType) {
24-
case(PARSE_SERVICE):
25-
return parseService(task);
26-
27-
case(VALIDATE_SERVER_CODE):
28-
return validateServerCode(task, runnerOpts);
29-
30-
default:
31-
throw new Error(`Unknown action type: [${task.actionType}]`);
32-
}
33-
};
34-
358
/**
369
* @param {InvokeActionTask} task
3710
*/
@@ -43,10 +16,48 @@ function parseService(task) {
4316
throw new Error('Not implemented yet');
4417
}
4518

46-
function validateServerCode(task, runnerOpts) {
19+
/**
20+
* @param {InvokeActionTask} task
21+
* @param {Object} runnerOpts
22+
*
23+
* @returns {String} ServerCodeModel JSON
24+
*/
25+
function analyseServerCode(task, runnerOpts) {
4726
const codePath = path.resolve(`${runnerOpts.repoPath}}/${task.relativePath}`);
4827

4928
const files = file.expand([`${codePath}/**`], { nodir: true });
5029

5130
return JSON.stringify(ServerCodeModel.build(codePath, files));
52-
}
31+
}
32+
33+
function shutdown() {
34+
logger.info('Received a shutdown request from Backendless');
35+
process.exit(0);
36+
}
37+
38+
const actions = {
39+
PARSE_CUSTOM_SERVICE_FROM_JAR: parseService,
40+
ANALYSE_SERVER_CODE : analyseServerCode,
41+
SHUTDOWN : shutdown
42+
};
43+
44+
/**
45+
* @typedef {CodeRunnerTask} InvokeActionTask
46+
* @property {String} actionType
47+
* @property {Object} argObject
48+
*/
49+
50+
/**
51+
* @param {InvokeActionTask} task
52+
* @param {Object} runnerOpts
53+
* @returns {*} Task Execution Result
54+
*/
55+
module.exports = function(task, runnerOpts) {
56+
const action = actions[task.actionType];
57+
58+
if (!action) {
59+
throw new Error(`Unknown action type: [${task.actionType}]`);
60+
}
61+
62+
return action(task, runnerOpts);
63+
};

lib/server-code/runners/tasks/invoke-method.js renamed to lib/server-code/runners/tasks/invoke-handler.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ const TIMED_OUT_ERR = 'Task execution aborted due to timeout';
1414
const defaultClassMappings = { [Backendless.User.prototype.___class]: Backendless.User };
1515

1616
/**
17-
* @typedef {CodeRunnerTask} InvokeMethodTask
17+
* @typedef {CodeRunnerTask} InvokeHandlerTask
1818
* @property {number} eventId
1919
* @property {string} target
2020
* @property {boolean} async
2121
* @property {Array.<number>} arguments
2222
*/
2323

2424
/**
25-
* @param {InvokeMethodTask} task
25+
* @param {InvokeHandlerTask} task
2626
* @param {Object} runnerOpts
2727
* @param {ServerCodeModel} model
2828
* @returns {Promise.<?Array<number>>}
@@ -98,7 +98,7 @@ module.exports = function(task, runnerOpts, model) {
9898
};
9999

100100
/**
101-
* @param {InvokeMethodTask} task
101+
* @param {InvokeHandlerTask} task
102102
* @param {Object} runnerOpts
103103
* @returns {ServerCodeModel}
104104
*/

test/invoke-action-task.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
const executor = require('../lib/server-code/runners/tasks/executor');
4+
const should = require('should');
5+
const SHUTDOWN = 'SHUTDOWN';
6+
7+
require('mocha');
8+
9+
/**
10+
* @param {String} actionType
11+
* @returns {CodeRunnerTask}
12+
*/
13+
function createTask(actionType) {
14+
return {
15+
___jsonclass: executor.RAI,
16+
actionType : actionType
17+
};
18+
}
19+
20+
describe('[invoke-action] task executor', function() {
21+
describe('on SHUTDOWN action', function() {
22+
it('should stop the CodeRunner process', function() {
23+
const exit = process.exit;
24+
let exitCalled = false;
25+
26+
process.exit = function() {
27+
exitCalled = true;
28+
};
29+
30+
process.exit.restore = function() {
31+
process.exit = exit;
32+
};
33+
34+
return executor.execute(createTask(SHUTDOWN), {})
35+
.then(process.exit.restore, process.exit.restore)
36+
.then(() => should.equal(exitCalled, true));
37+
});
38+
});
39+
});

test/rmi-task.js renamed to test/invoke-handler-task.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ const should = require('should'),
1111

1212
require('mocha');
1313

14-
const INVOKE_METHOD_TASK = 'com.backendless.coderunner.commons.protocol.RequestMethodInvocation';
15-
1614
function stringToBytes(s) {
1715
return s.split('').map((c, i) => s.charCodeAt(i));
1816
}
@@ -34,7 +32,7 @@ function modelStub(handlerFn, classMappings) {
3432

3533
function createTask(event, args, async) {
3634
return {
37-
___jsonclass: INVOKE_METHOD_TASK,
35+
___jsonclass: executor.RMI,
3836
eventId : event.id,
3937
async : !!async,
4038
initAppData : {},
@@ -53,7 +51,7 @@ function invokeAndParse(task, model) {
5351
});
5452
}
5553

56-
describe('[invoke-method] task executor', function() {
54+
describe('[invoke-handler] task executor', function() {
5755
it('should fill [request] params', function() {
5856
const task = createTask(BEFORE_CREATE, [{}, { name: 'John' }]);
5957

0 commit comments

Comments
 (0)