1

What I want to do is when an endpoint in my Express app is hit, I want to run a command line script - without waiting for the result - in a separate process.

Right now I am using the child_process’s spawn function and it is working, but if the Node server were to quit, the child script would quit as well. I need to have the child script run to completion even if the server quits.

I don’t need access to stdout or anything from the child script. I just need a way to basically “fire and forget”

Is there any way to do this with spawn that I may be missing? Or is there another way I should be going about this?

Thanks in advance for any guidance!

1
  • 1
    I believe that's detached. Don't have a quick moment for the test case, but the documentation would seem to point that way. Commented Apr 15, 2018 at 2:37

1 Answer 1

7

What you want here is options.detached of spawn. Setting this option will allow the sub-process to continue even after the main process calling spawn has terminated.

Quoting the documentation:

On Windows, setting options.detached to true makes it possible for the child process to continue running after the parent exits. The child will have its own console window. Once enabled for a child process, it cannot be disabled.

On non-Windows platforms, if options.detached is set to true, the child process will be made the leader of a new process group and session. Note that child processes may continue running after the parent exits regardless of whether they are detached or not. See setsid(2) for more information.

Basically this means what you "launch" keeps running until it actually terminates itself. As 'detached', there is nothing that "ties" the sub-process to the execution of the parent from which it was spawned.

Example:

listing of sub.js:

(async function() {

  try {

    await new Promise((resolve,reject) => {
      let i = 0;
      let ival = setInterval(() => {
        i++;
        console.log('Run ',i);
        if (i === 5) {
          clearInterval(ival);
          resolve();
        }
      }, 2000);
    });

  } catch(e) {
    console.error(e);
  } finally {
    process.exit();
  }

})();

listing of main.js

const fs = require('fs');
const { spawn } = require('child_process');

(async function() {

  try {

    const out = fs.openSync('./out.log', 'a');
    const err = fs.openSync('./out.log', 'a');

    console.log('spawn sub');

    const sub = spawn(process.argv[0], ['sub.js'], {
      detached: true,               // this removes ties to the parent
      stdio: [ 'ignore', out, err ]
    });

    sub.unref();
    console.log('waiting..');

    await new Promise((resolve,reject) =>
      setTimeout(() => resolve(), 3000)
    );
    console.log('exiting main..');

  } catch(e) {
    console.error();
  } finally {
    process.exit();
  }

})();

The basics there are that the sub.js listing is going to output every 2 seconds for 5 iterations. The main.js is going to "spawn" this process as detached, then wait for 3 seconds and terminate itself.

Though it's not really needed, for demonstration purposes we are setting up the spawned sub-process to redirect its output ( both stdout and stderr ) to a file named out.log in the same directory.

What you see here is that the main listing does it's job and spawns the new process then terminates after 3 seconds. At this time the sub-process will only have output 1 line, but it will continue to run and produce output to the redirected file for another 7 seconds, despite the main process being terminated.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot! I knew I must’ve been missing something obvious!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.