mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
adding timeout attribute to function node
- [x] New feature (non-breaking change which adds functionality) Discussion here: https://discourse.nodered.org/t/function-node-doesnt-have-timeout-feature/78483 ## Proposed changes Adding a timeout attribute to the function node, so an endless funciton doesnt break the node red server. ## Checklist - [x] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md) - [x] For non-bugfix PRs, I have discussed this change on the forum/slack team. - [x] I have run `grunt` to verify the unit tests pass - [x] I have added suitable unit tests to cover the new/changed functionality
This commit is contained in:
parent
67dd7e30fa
commit
2253417459
@ -82,6 +82,11 @@
|
||||
<input id="node-input-outputs" style="width: 60px;" value="1">
|
||||
</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;" value="1000">
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
@ -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() {
|
||||
|
@ -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) {
|
||||
@ -397,8 +412,11 @@ module.exports = function(RED) {
|
||||
context.msg = msg;
|
||||
context.__send__ = send;
|
||||
context.__done__ = done;
|
||||
|
||||
node.script.runInContext(context);
|
||||
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) {
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -212,7 +212,8 @@
|
||||
"function": "Функция",
|
||||
"initialize": "Настройка",
|
||||
"finalize": "Закрытие",
|
||||
"outputs": "Выходы"
|
||||
"outputs": "Выходы",
|
||||
"timeout":"Время ожидания (мс)"
|
||||
},
|
||||
"text": {
|
||||
"initialize": "// Добавленный здесь код будет исполняться\n// однократно при развертывании узла.\n",
|
||||
|
@ -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() {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user