1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Merge pull request #4177 from k1ln/adding-timeout-to-functio-node

adding timeout attribute to function node
This commit is contained in:
Nick O'Leary 2023-06-21 15:57:44 +01:00 committed by GitHub
commit ce679f90ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 78 additions and 8 deletions

View File

@ -82,6 +82,11 @@
<input id="node-input-outputs" style="width: 60px;" value="1"> <input id="node-input-outputs" style="width: 60px;" value="1">
</div> </div>
<div class="form-row">
<label for="node-input-timeout"><i class="fa fa-clock"></i> <span data-i18n="function.label.timeout"></span></label>
<input id="node-input-timeout" style="width: 60px;" data-i18n="[placeholder]join.seconds">
</div>
<div class="form-row node-input-libs-row hide" style="margin-bottom: 0px;"> <div class="form-row node-input-libs-row hide" style="margin-bottom: 0px;">
<label><i class="fa fa-cubes"></i> <span data-i18n="function.label.modules"></span></label> <label><i class="fa fa-cubes"></i> <span data-i18n="function.label.modules"></span></label>
</div> </div>
@ -360,6 +365,7 @@
name: {value:"_DEFAULT_"}, name: {value:"_DEFAULT_"},
func: {value:"\nreturn msg;"}, func: {value:"\nreturn msg;"},
outputs: {value:1}, outputs: {value:1},
timeout:{value:0},
noerr: {value:0,required:true, noerr: {value:0,required:true,
validate: function(v, opt) { validate: function(v, opt) {
if (!v) { 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 buildEditor = function(id, stateId, focus, value, defaultValue, extraLibs, offset) {
var editor = RED.editor.createEditor({ var editor = RED.editor.createEditor({
id: id, id: id,
@ -503,7 +529,7 @@
editor:this.editor, // the field name the main text body goes to editor:this.editor, // the field name the main text body goes to
mode:"ace/mode/nrjavascript", mode:"ace/mode/nrjavascript",
fields:[ fields:[
'name', 'outputs', 'name', 'outputs', 'timeout',
{ {
name: 'initialize', name: 'initialize',
get: function() { get: function() {

View File

@ -96,6 +96,13 @@ module.exports = function(RED) {
node.name = n.name; node.name = n.name;
node.func = n.func; node.func = n.func;
node.outputs = n.outputs; 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.ini = n.initialize ? n.initialize.trim() : "";
node.fin = n.finalize ? n.finalize.trim() : ""; node.fin = n.finalize ? n.finalize.trim() : "";
node.libs = n.libs || []; node.libs = n.libs || [];
@ -362,6 +369,10 @@ module.exports = function(RED) {
})(__initSend__);`; })(__initSend__);`;
iniOpt = createVMOpt(node, " setup"); iniOpt = createVMOpt(node, " setup");
iniScript = new vm.Script(iniText, iniOpt); iniScript = new vm.Script(iniText, iniOpt);
if(node.timeout>0){
iniOpt.timeout = node.timeout;
iniOpt.breakOnSigint = true;
}
} }
node.script = vm.createScript(functionText, createVMOpt(node, "")); node.script = vm.createScript(functionText, createVMOpt(node, ""));
if (node.fin && (node.fin !== "")) { if (node.fin && (node.fin !== "")) {
@ -385,6 +396,10 @@ module.exports = function(RED) {
})();`; })();`;
finOpt = createVMOpt(node, " cleanup"); finOpt = createVMOpt(node, " cleanup");
finScript = new vm.Script(finText, finOpt); finScript = new vm.Script(finText, finOpt);
if(node.timeout>0){
finOpt.timeout = node.timeout;
finOpt.breakOnSigint = true;
}
} }
var promise = Promise.resolve(); var promise = Promise.resolve();
if (iniScript) { if (iniScript) {
@ -397,8 +412,11 @@ module.exports = function(RED) {
context.msg = msg; context.msg = msg;
context.__send__ = send; context.__send__ = send;
context.__done__ = done; context.__done__ = done;
var opts = {};
node.script.runInContext(context); if (node.timeout>0){
opts = node.timeoutOptions;
}
node.script.runInContext(context,opts);
context.results.then(function(results) { context.results.then(function(results) {
sendResults(node,send,msg._msgid,results,false); sendResults(node,send,msg._msgid,results,false);
if (handleNodeDoneCall) { if (handleNodeDoneCall) {

View File

@ -216,7 +216,8 @@
"initialize": "Start", "initialize": "Start",
"finalize": "Stopp", "finalize": "Stopp",
"outputs": "Ausgänge", "outputs": "Ausgänge",
"modules": "Module" "modules": "Module",
"timeout": "Timeout"
}, },
"text": { "text": {
"initialize": "// Der Code hier wird ausgeführt,\n// wenn der Node gestartet wird\n", "initialize": "// Der Code hier wird ausgeführt,\n// wenn der Node gestartet wird\n",

View File

@ -252,7 +252,8 @@
"initialize": "On Start", "initialize": "On Start",
"finalize": "On Stop", "finalize": "On Stop",
"outputs": "Outputs", "outputs": "Outputs",
"modules": "Modules" "modules": "Modules",
"timeout": "Timeout"
}, },
"text": { "text": {
"initialize": "// Code added here will be run once\n// whenever the node is started.\n", "initialize": "// Code added here will be run once\n// whenever the node is started.\n",

View File

@ -212,7 +212,8 @@
"function": "Функция", "function": "Функция",
"initialize": "Настройка", "initialize": "Настройка",
"finalize": "Закрытие", "finalize": "Закрытие",
"outputs": "Выходы" "outputs": "Выходы",
"timeout":"Время ожидания"
}, },
"text": { "text": {
"initialize": "// Добавленный здесь код будет исполняться\n// однократно при развертывании узла.\n", "initialize": "// Добавленный здесь код будет исполняться\n// однократно при развертывании узла.\n",

View File

@ -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() { describe("finalize function", function() {