diff --git a/packages/node_modules/@node-red/nodes/core/function/10-function.html b/packages/node_modules/@node-red/nodes/core/function/10-function.html
index e17f58aca..581c58c73 100644
--- a/packages/node_modules/@node-red/nodes/core/function/10-function.html
+++ b/packages/node_modules/@node-red/nodes/core/function/10-function.html
@@ -82,6 +82,11 @@
+
+
+
+
+
@@ -360,6 +365,7 @@
name: {value:"_DEFAULT_"},
func: {value:"\nreturn msg;"},
outputs: {value:1},
+ timeout:{value:0},
noerr: {value:0,required:true,
validate: function(v, opt) {
if (!v) {
@@ -464,6 +470,26 @@
}
});
+ // 4294967 is max in node.js timeout.
+ $( "#node-input-timeout" ).spinner({
+ min: 0,
+ max: 4294967,
+ change: function(event, ui) {
+ var value = this.value;
+ if(value == ""){
+ value = 0;
+ }
+ else
+ {
+ value = parseInt(value);
+ }
+ value = isNaN(value) ? 1 : value;
+ value = Math.max(value, parseInt($(this).attr("aria-valuemin")));
+ value = Math.min(value, parseInt($(this).attr("aria-valuemax")));
+ if (value !== this.value) { $(this).spinner("value", value); }
+ }
+ });
+
var buildEditor = function(id, stateId, focus, value, defaultValue, extraLibs, offset) {
var editor = RED.editor.createEditor({
id: id,
@@ -503,7 +529,7 @@
editor:this.editor, // the field name the main text body goes to
mode:"ace/mode/nrjavascript",
fields:[
- 'name', 'outputs',
+ 'name', 'outputs', 'timeout',
{
name: 'initialize',
get: function() {
diff --git a/packages/node_modules/@node-red/nodes/core/function/10-function.js b/packages/node_modules/@node-red/nodes/core/function/10-function.js
index b69f6eeed..a6ede375f 100644
--- a/packages/node_modules/@node-red/nodes/core/function/10-function.js
+++ b/packages/node_modules/@node-red/nodes/core/function/10-function.js
@@ -96,6 +96,13 @@ module.exports = function(RED) {
node.name = n.name;
node.func = n.func;
node.outputs = n.outputs;
+ node.timeout = n.timeout*1000;
+ if(node.timeout>0){
+ node.timeoutOptions = {
+ timeout:node.timeout,
+ breakOnSigint:true
+ }
+ }
node.ini = n.initialize ? n.initialize.trim() : "";
node.fin = n.finalize ? n.finalize.trim() : "";
node.libs = n.libs || [];
@@ -362,6 +369,10 @@ module.exports = function(RED) {
})(__initSend__);`;
iniOpt = createVMOpt(node, " setup");
iniScript = new vm.Script(iniText, iniOpt);
+ if(node.timeout>0){
+ iniOpt.timeout = node.timeout;
+ iniOpt.breakOnSigint = true;
+ }
}
node.script = vm.createScript(functionText, createVMOpt(node, ""));
if (node.fin && (node.fin !== "")) {
@@ -385,6 +396,10 @@ module.exports = function(RED) {
})();`;
finOpt = createVMOpt(node, " cleanup");
finScript = new vm.Script(finText, finOpt);
+ if(node.timeout>0){
+ finOpt.timeout = node.timeout;
+ finOpt.breakOnSigint = true;
+ }
}
var promise = Promise.resolve();
if (iniScript) {
@@ -396,9 +411,12 @@ module.exports = function(RED) {
var start = process.hrtime();
context.msg = msg;
context.__send__ = send;
- context.__done__ = done;
-
- node.script.runInContext(context);
+ context.__done__ = done;
+ var opts = {};
+ if (node.timeout>0){
+ opts = node.timeoutOptions;
+ }
+ node.script.runInContext(context,opts);
context.results.then(function(results) {
sendResults(node,send,msg._msgid,results,false);
if (handleNodeDoneCall) {
diff --git a/packages/node_modules/@node-red/nodes/locales/de/messages.json b/packages/node_modules/@node-red/nodes/locales/de/messages.json
index 828cd4252..bc706e1f1 100644
--- a/packages/node_modules/@node-red/nodes/locales/de/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/de/messages.json
@@ -216,7 +216,8 @@
"initialize": "Start",
"finalize": "Stopp",
"outputs": "Ausgänge",
- "modules": "Module"
+ "modules": "Module",
+ "timeout": "Timeout"
},
"text": {
"initialize": "// Der Code hier wird ausgeführt,\n// wenn der Node gestartet wird\n",
diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
index 2f282036c..a7b583878 100644
--- a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
@@ -252,7 +252,8 @@
"initialize": "On Start",
"finalize": "On Stop",
"outputs": "Outputs",
- "modules": "Modules"
+ "modules": "Modules",
+ "timeout": "Timeout"
},
"text": {
"initialize": "// Code added here will be run once\n// whenever the node is started.\n",
diff --git a/packages/node_modules/@node-red/nodes/locales/ru/messages.json b/packages/node_modules/@node-red/nodes/locales/ru/messages.json
index 32364b458..58ccf90fe 100644
--- a/packages/node_modules/@node-red/nodes/locales/ru/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/ru/messages.json
@@ -212,7 +212,8 @@
"function": "Функция",
"initialize": "Настройка",
"finalize": "Закрытие",
- "outputs": "Выходы"
+ "outputs": "Выходы",
+ "timeout":"Время ожидания"
},
"text": {
"initialize": "// Добавленный здесь код будет исполняться\n// однократно при развертывании узла.\n",
diff --git a/test/nodes/core/function/10-function_spec.js b/test/nodes/core/function/10-function_spec.js
index 4f7f0b806..99557f0b3 100644
--- a/test/nodes/core/function/10-function_spec.js
+++ b/test/nodes/core/function/10-function_spec.js
@@ -1424,7 +1424,30 @@ describe('function node', function() {
});
});
-
+ it('should timeout if timeout is set', function(done) {
+ var flow = [{id:"n1",type:"function",wires:[["n2"]],timeout:"0.010",func:"while(1==1){};\nreturn msg;"}];
+ helper.load(functionNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ n1.receive({payload:"foo",topic: "bar"});
+ setTimeout(function() {
+ try {
+ helper.log().called.should.be.true();
+ var logEvents = helper.log().args.filter(function(evt) {
+ return evt[0].type == "function";
+ });
+ logEvents.should.have.length(1);
+ var msg = logEvents[0][0];
+ msg.should.have.property('level', helper.log().ERROR);
+ msg.should.have.property('id', 'n1');
+ msg.should.have.property('type', 'function');
+ should.equal(msg.msg.message, 'Script execution timed out after 10ms');
+ done();
+ } catch(err) {
+ done(err);
+ }
+ },50);
+ });
+ });
describe("finalize function", function() {