Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Electron kill child_process.exec

Tags:

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.

If they exit my app or hit close the child processes continue to run until they finish however the electron app window has already closed and exited.

Is there a way to notify the user that there are process still running and when they have finished then close the app window?

All I have in my main.js is the standard code:

// Quit when all windows are closed.
app.on('window-all-closed', function() {
    // On OS X it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform != 'darwin') {
        app.quit();
    }
});

Should I be adding a check somewhere?

Thanks for your help

EDITED

I cannot seem to get the PID of the child_process until it has finished. This is my child_process code

var loader = child_process.exec(cmd, function(error, stdout, stderr) {
    console.log(loader.pid)
    if (error) {
        console.log(error.message);
    }
    console.log('Loaded: ', value);
});

Should I be trying to get it in a different way?

like image 572
tjmgis Avatar asked Mar 16 '16 09:03

tjmgis


2 Answers

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.

like image 83
tjmgis Avatar answered Sep 20 '22 01:09

tjmgis


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!

like image 25
Joe Clay Avatar answered Sep 21 '22 01:09

Joe Clay