Electron kill child_process.exec

后端 未结 3 964
旧巷少年郎
旧巷少年郎 2021-02-04 05:15

I have an electron app that uses child_process.exec to run long running tasks. I am struggling to manage when the user exits the app during those tasks.

I

相关标签:
3条回答
  • 2021-02-04 05:28

    Another solution. If you want to keep using exec()

    In order to kill the child process running by exec() take a look to the module ps-tree. They exaplain what is happening.

    in UNIX, a process may terminate by using the exit call, and it's parent process may wait for that event by using the wait system call. the wait system call returns the process identifier of a terminated child, so that the parent tell which of the possibly many children has terminated. If the parent terminates, however, all it's children have assigned as their new parent the init process. Thus, the children still have a parent to collect their status and execution statistics. (from "operating system concepts")

    SOLUTION: use ps-tree to get all processes that a child_process may have started, so that they

    exec() actually works like this:

    function exec (cmd, cb) {
      spawn('sh', ['-c', cmd]);
      ...
    }
    

    So check the example and adapt it to your needs

    var cp = require('child_process'),
    psTree = require('ps-tree');
    
    var child = cp.exec("node -e 'while (true);'", function () { /*...*/ });
    
    psTree(child.pid, function (err, children) {
        cp.spawn('kill', ['-9'].concat(children.map(function (p) { return p.PID })));
    });
    
    0 讨论(0)
  • 2021-02-04 05:39

    ChildProcess emits an exit event when the process has finished - if you keep track of the current processes in an array, and have them remove themselves after the exit event fires, you should be able to just foreach over the remaining ones running ChildProcess.kill() when you exit your app.

    This may not be 100% working code/not the best way of doing things, as I'm not in a position to test it right now, but it should be enough to set you down the right path.

    var processes = [];
    
    // Adding a process
    var newProcess = child_process.exec("mycommand");
    processes.push(newProcess);
    newProcess.on("exit", function () {
      processes.splice(processes.indexOf(newProcess), 1);
    });
    
    // App close handler
    app.on('window-all-closed', function() {
      if (process.platform != 'darwin') {
        processes.forEach(function(proc) {
          proc.kill();
        });
    
        app.quit();
      }
    });
    

    EDIT: As shreik mentioned in a comment, you could also just store the PIDs in the array instead of the ChildProcess objects, then use process.kill(pid) to kill them. Might be a little more efficient!

    0 讨论(0)
  • 2021-02-04 05:45

    So after everyones great comments I was able to update my code with a number of additions to get it to work, so am posting my updates for everyone else.

    1) Change from child_process.exec to child_process.spawn

    var loader = child_process.spawn('program', options, { detached: true })

    2) Use the Electron ipcRenderer to communicate from my module to the main.js script. This allows me to send the PIDs to main.js

    ipcRenderer.send('pid-message', loader.pid);

    ipcMain.on('pid-message', function(event, arg) {
      console.log('Main:', arg);
      pids.push(arg);
    });
    

    3) Add those PIDs to array

    4) In my main.js I added the following code to kill any PIDs that exist in the array before exiting the app.

    // App close handler
    app.on('before-quit', function() {
      pids.forEach(function(pid) {
        // A simple pid lookup
        ps.kill( pid, function( err ) {
            if (err) {
                throw new Error( err );
            }
            else {
                console.log( 'Process %s has been killed!', pid );
            }
        });
      });
    });
    

    Thanks for everyones help.

    0 讨论(0)
提交回复
热议问题