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..8130be2ad 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 @@ } }); + // 4294967295 is max in node.js timeout. + $( "#node-input-timeout" ).spinner({ + min: 0, + max: 4294967294, + 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 b84ee8571..3ada08943 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*1; + 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 65f251e98..2efd2b86d 100644 --- a/packages/node_modules/@node-red/nodes/locales/de/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/de/messages.json @@ -214,7 +214,8 @@ "initialize": "Start", "finalize": "Stopp", "outputs": "Ausgänge", - "modules": "Module" + "modules": "Module", + "timeout": "Timeout (ms)" }, "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 9c055d47b..7fc5912bb 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 @@ -248,7 +248,8 @@ "initialize": "On Start", "finalize": "On Stop", "outputs": "Outputs", - "modules": "Modules" + "modules": "Modules", + "timeout": "Timeout (ms)" }, "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..0fac5118e 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..e5b689136 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:"10",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() {