1

I use the following code to create child process, the process is working as expected, what I want to do now is at the end of the process kill it , I try with the last then (which if I put BP it stops there after the process done) my question is how to kill it properly and avoid this error.

getCmd provide the command to run and this is working as expected

var childProcess = Promise.promisify(require('child_process').exec);

....
            .then(getCmd)
            .then(childProcess)
            .spread(function (stdout, stderr) {
                console.log(stdout, stderr);
                return stdout;
            }).then(function(){

                childProcess.kill()
            })

when the line childProcess.kill() is executed I got error :

[TypeError: undefined is not a function]

How to overcome this issue and kill the process at the end

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I am not sure, but if Promise.promisify returns a promise like in angular, then that promise might not be the childProcess object itself. Try using then(function(process) { process.kill(); } – Lars Juel Jensen Aug 05 '15 at 12:20
  • Or maybe just store the process handle in a variable and use that variable in the last then like this: var chldPrc = require('child_process').exec; ... ... ... chldPrc.kill(); – Lars Juel Jensen Aug 05 '15 at 12:22
  • @LarsJuelJensen - thanks but not sure I got your last comment,can you provide example? –  Aug 05 '15 at 12:24
  • Isn't there just a destructor that will clean things up? `delete childProcess;` – Xyv Aug 05 '15 at 13:27
  • You're not using both `Q` and `Bluebird`, do you? Please tag your question accordingly. Remove both if you're not targeting a specific promise implementation. – Bergi Aug 05 '15 at 19:24
  • @Bergi - I use bluebird (promsifiy...),one thing that I've notice now that if I put console.log("test") instead the childProcess.kill() i got undifend,any idea why? what I need is that when the child process end kill it...can you assist please? –  Aug 05 '15 at 20:06
  • @Bergi - if I remove the last then I dont get any error and the child process is executed correct but not killed .... –  Aug 05 '15 at 20:09
  • I'm still having a hard time understanding what you actually want to do. Starting a child process and then immediately killing it doesn't seem useful. *When* do you want to kill it? "*at the end*" of what? – Bergi Aug 05 '15 at 20:16
  • @Bergi - assume that I execute childProcess commend like npm install bluebird -g this command is executed and when it finish (I see in the log that the command was exe. in log) kill it , if you have other idea where its good time to kill it please provide me example how you would do it.Thanks in advance! –  Aug 05 '15 at 20:35
  • Why would you need to kill it at all when you want to let it finish normally??? – Bergi Aug 05 '15 at 20:39
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/85241/discussion-between-mark-and-bergi). –  Aug 05 '15 at 20:43
  • @Bergi - Assume that my node application was up and create child process and after a while the node app is down,I dont need to verify that this process is killed somehow ? –  Aug 05 '15 at 20:48

2 Answers2

0

As requested, an example:

var childProcess = require('child_process').exec;
var childPromise = Promise.promisify(childProcess);

....
childPromise
            .then(getCmd)
            .then(childPromise) // not sure if you want the promise or process here
            .spread(function (stdout, stderr) {
                console.log(stdout, stderr);
                return stdout;
            }).then(function(){

                childProcess.kill() // as returned by require(...).exec
            })
Lars Juel Jensen
  • 1,643
  • 1
  • 22
  • 31
  • Thanks I've changed the code like your example and im getting the same error ,why ? if I remove the last then I dont get this error...maybe I need to supply process id ? if yes do you know how? –  Aug 05 '15 at 14:10
  • I'm not really sure. Not that familiar with NodeJS (which I assume you are using). Also I have a hard time figuring out which process you are running. At least the childProcess variable does not contain any information about it. – Lars Juel Jensen Aug 05 '15 at 14:17
  • Perhaps you need to do something more like this: var exec = require(...).exec; var childProcess = exec("ls -l"); – Lars Juel Jensen Aug 05 '15 at 14:18
  • There are more info about the exec call here -> https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback, and about the kill call here -> https://nodejs.org/api/child_process.html#child_process_child_kill_signal – Lars Juel Jensen Aug 05 '15 at 14:19
  • Also, what is getCmd? Perhaps all you need to do is getCmd.kill(); ? – Lars Juel Jensen Aug 05 '15 at 14:20
  • 1
    You can also have a look at this question -> http://stackoverflow.com/questions/30763496/how-to-promisify-nodes-child-process-exec-and-child-process-execfile-functions – Lars Juel Jensen Aug 05 '15 at 14:27
0

As far as I can tell, promisifying require('child_process').exec itself is not correct. At best, you would end up with a function that returns a promise but you would, straightforwardly, be denied a reference to the child-process itself. Some imagination is required.

You can call require('child_process').exec(cmd, callback) in the normal way, inside a new Promise() wrapper and, critically, resolve/reject in such a way that a reference to the child-process is made available down the promise chain.

I'm not sure that Bluebird's .promisify() is quite flexible enough to do the job so here's a manual promisification.

First a couple or requires :

var Promise = require('bluebird');
var child_process = require('child_process');

Now the manual promisifier :

function childProcessPromise (method, cmd) {
    return new Promise(function(resolve, reject) {
        var child = child_process[method](cmd, function(error, stdout, stderr) {
            if(error !== null) {
                error.child = child;//monkeypatch the error with a custom .child property.
                reject(error);
            } else {
                resolve({ 'child':child, 'stdout':stdout, 'stderr':stderr });//all available data bundled into a single object.
            }
        });
    });
}

As written this promisifier is flexible enough to cater for various child_process methods. Just pass (or bind) 'spawn', 'exec', 'execFile' or 'fork' as first parameter.

Your promise chain will look like this :

....
    .then(getCmd)
    .then(childProcessPromise.bind(null, 'exec'))
    .then(function(result) {
        // result.child, result.stdout and result.stderr are available here.
    }, function(error) {
        //error is available here, including its custom .child property.
    });

All untested, so be prepared to adapt/fix.

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
  • Thanks a lot 1+ ,its not working...while debug it I see that the right cmd and method are filled correct...in the following function var child = child_process[method](cmd, function (error, stdout, stderr) { –  Aug 07 '15 at 07:03
  • But it's not stops in the if after if(error !== null) { and I dont get any error ... if(error !== null) { any idea ???? –  Aug 07 '15 at 07:04
  • According to what I read, `error` should be an instance of `Error`. Can you check whether that is correct please? – Roamer-1888 Aug 07 '15 at 07:35
  • HI, How to check it ? –  Aug 07 '15 at 07:52
  • Thanks It seems that now it works but it take time to exec the command ,any idea why it's taking so long? the code I use before work much faster.. –  Aug 07 '15 at 07:58
  • Any delay will be the process's run time. – Roamer-1888 Aug 07 '15 at 08:00
  • BTW, the callback runs on termination of the child process so I can't see why you would need to kill something that's already terminated. Is there a particular reason? – Roamer-1888 Aug 07 '15 at 08:03
  • Thanks a lot, assume that I want to kill the process after it excute the command, how should I do that ? –  Aug 07 '15 at 08:03
  • So you are saying theat I dont need to kill the process? –  Aug 07 '15 at 08:04
  • As far as I can tell, no. At least not in this way. If the process needs killing then the kill command would need to be issued in some other block of code. The callback (and hence settlement of the the promise) will run when the process terminates for whatever reason. – Roamer-1888 Aug 07 '15 at 08:08
  • 1
    Ok So assume I need to keep the instance of the childProcess to kill in other request how you would do it ? I mean If I've method _excecuteCmd and I need addtional method killProcess how would you do it in the same module and keep the instance from the exec command that for given requet(kill) it will kill the process ...thanks sir! –  Aug 07 '15 at 08:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/85401/discussion-between-roamer-1888-and-mark). – Roamer-1888 Aug 07 '15 at 09:24