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

let exec node take msg.kill SIG... param and pid param

and redo test
This commit is contained in:
Dave Conway-Jones 2017-03-06 15:27:29 +00:00
parent 4a8a5ed8d4
commit c6436f47eb
3 changed files with 70 additions and 20 deletions

View File

@ -46,22 +46,23 @@
<script type="text/x-red" data-help-name="exec"> <script type="text/x-red" data-help-name="exec">
<p>Calls out to a system command.<br/></p> <p>Calls out to a system command.<br/></p>
<p>Provides 3 outputs: stdout, stderr, and return code.</p> <p>Provides 3 outputs: stdout, stderr, and return code.</p>
<p>By default uses the <code>exec</code> system call which calls the command, then gets a callback <p>By default uses the <code>exec</code> system call which calls the command, waits for it to complete, and
on completion, returning stdout as the payload to the first, the error code as the third returns the normal output to the first port, any error text to the second port, and a return code object to the
and, if available, stderr to the second output. If no error occurred, a zero is returned on the third output.</p> third port. For example a succesful command should return <code>{ code: 0 }</code>.</p>
<p>Optionally can use <code>spawn</code> instead, which returns the output from stdout and stderr <p>Optionally can use <code>spawn</code> instead, which returns the output from stdout and stderr
as the command runs (usually one line at a time). On completion it then returns a return code as the command runs, usually one line at a time. On completion it then returns a numeric return code
(on the 3rd output).</p> on the 3rd port. For example a successful command should return <code>0</code>.</p>
<p>The <code>exec</code> method spawns a subshell and therefore can be used for more complicated <p>The <code>exec</code> method spawns a subshell and therefore can be used for more complicated
commands involving pipes. However, it waits for completion of the whole command before returing anything.</p> commands involving pipes. However, it waits for completion of the whole command before returing anything.</p>
<p>The optional append gets added to the command after <code>msg.payload</code> - so you can do <p>The optional <b>append</b> gets added to the command after <code>msg.payload</code> - so you can do
things like pipe the result to another command.</p> things like pipe the result to another command.</p>
<p>Commands or parameters with spaces should be enclosed in quotes - <i>"This is a single parameter"</i></p> <p>Commands or parameters with spaces should be enclosed in quotes - <i>"This is a single parameter"</i></p>
<p>If stdout is binary a <i>buffer</i> is returned - otherwise returns a <i>string</i>.</p> <p>The <code>payload</code> is usually a <i>string</i>, unless binary is detected, in which case it contains a <i>buffer</i>.</p>
<p>The blue status icon and PID will be visible while the node is active.</p> <p>The blue status icon and PID will be visible while the node is active. This can be read by a <code>status</code> node.</p>
<p>Sending <code>msg.kill</code> will kill a single active process. If there is more than one process running then <p>Sending <code>msg.kill</code> will kill a single active process. <code>msg.kill</code> should be a string containing
<code>msg.kill</code> must be set with the value of the PID to be killed.</p> the type of signal to be sent, e.g. "SIGINT", "SIGQUIT", "SIGHUP", etc. Defaults to "SIGTERM" if blank ("").
<p>Tip: If running a Python app you may need to use the <code>-u</code> parameter to stop the output being buffered.</p> If there is more than one process running then <code>msg.pid</code> must also be set with the value of the PID to be killed.</p>
<p><b>Tip: </b>If running a Python app you may need to use the <code>-u</code> parameter to stop the output being buffered.</p>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
@ -78,7 +79,7 @@
}, },
inputs:1, inputs:1,
outputs:3, outputs:3,
outputLabels: ["stdout","stderr","rc"], outputLabels: ["stdout","stderr","return code"],
icon: "arrow-in.png", icon: "arrow-in.png",
align: "right", align: "right",
label: function() { label: function() {

View File

@ -39,13 +39,16 @@ module.exports = function(RED) {
this.on("input", function(msg) { this.on("input", function(msg) {
if (msg.hasOwnProperty("kill")) { if (msg.hasOwnProperty("kill")) {
if (node.activeProcesses.hasOwnProperty(msg.kill) ) { if (typeof msg.kill !== "string" || msg.kill.length === 0 || !msg.kill.toUpperCase().startsWith("SIG") ) { msg.kill = ""; }
node.activeProcesses[msg.kill].kill(); if (msg.hasOwnProperty("pid")) {
node.status({fill:"red",shape:"dot",text:"killed"}); if (node.activeProcesses.hasOwnProperty(msg.pid) ) {
node.activeProcesses[msg.pid].kill(msg.kill.toUpperCase());
node.status({fill:"red",shape:"dot",text:"killed"});
}
} }
else { else {
if (Object.keys(node.activeProcesses).length === 1) { if (Object.keys(node.activeProcesses).length === 1) {
node.activeProcesses[Object.keys(node.activeProcesses)[0]].kill(); node.activeProcesses[Object.keys(node.activeProcesses)[0]].kill(msg.kill.toUpperCase());
node.status({fill:"red",shape:"dot",text:"killed"}); node.status({fill:"red",shape:"dot",text:"killed"});
} }
} }
@ -149,7 +152,7 @@ module.exports = function(RED) {
/* istanbul ignore else */ /* istanbul ignore else */
if (node.activeProcesses.hasOwnProperty(pid)) { if (node.activeProcesses.hasOwnProperty(pid)) {
if (node.activeProcesses[pid].tout) { clearTimeout(node.activeProcesses[pid].tout); } if (node.activeProcesses[pid].tout) { clearTimeout(node.activeProcesses[pid].tout); }
// console.log("KILLLING",pid); // console.log("KILLING",pid);
var process = node.activeProcesses[pid]; var process = node.activeProcesses[pid];
node.activeProcesses[pid] = null; node.activeProcesses[pid] = null;
process.kill(); process.kill();

View File

@ -239,7 +239,32 @@ describe('exec node', function() {
} }
}); });
setTimeout(function() { setTimeout(function() {
n1.receive({kill:true}); n1.receive({kill:""});
},150);
n1.receive({});
});
});
it('should be able to kill a long running command - SIGINT', function(done) {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2"},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
helper.load(execNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var n3 = helper.getNode("n3");
var n4 = helper.getNode("n4");
n4.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.have.property("killed",true);
msg.payload.should.have.property("signal","SIGINT");
done();
} catch(err) {
done(err);
}
});
setTimeout(function() {
n1.receive({kill:"sigint"});
},150); },150);
n1.receive({}); n1.receive({});
}); });
@ -509,7 +534,28 @@ describe('exec node', function() {
done(); done();
}); });
setTimeout(function() { setTimeout(function() {
n1.receive({kill:true}); n1.receive({kill:""});
},150);
n1.receive({});
});
});
it('should be able to kill a long running command - SIGQUIT', function(done) {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2"},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
helper.load(execNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var n3 = helper.getNode("n3");
var n4 = helper.getNode("n4");
n4.on("input", function(msg) {
msg.should.have.property("payload");
msg.payload.should.have.property("killed",true);
msg.payload.should.have.property("signal","SIGQUIT");
done();
});
setTimeout(function() {
n1.receive({kill:"sigquit"});
},150); },150);
n1.receive({}); n1.receive({});
}); });