Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detach a spawn child process after the start

I start a spawn child process this way:

let process = spawn(apiPath, {
  detached: true
})

process.unref()

process.stdout.on('data', data => { /* do something */ })

When I start the process I need to keep it attached because I want to read its output. But just before closing my Node process (the parent) I want to detach all not finished children processes to keep them running in background, but as the documentation say:

When using the detached option to start a long-running process, the process will not stay running in the background after the parent exits unless it is provided with a stdio configuration that is not connected to the parent.

But with the option stdio: 'ignore' I can't read the stdout which is a problem.

I tried to manually close the pipes before to close the parent process but it is unsuccessful:

// Trigger just before the main process end
process.stdin.end()
process.stderr.unpipe()
process.stdout.unpipe()
like image 509
Opsse Avatar asked Jan 08 '20 13:01

Opsse


1 Answers

After many tests I found at least one way to solve this problem : destroying all pipe before to leave the main process.

One tricky point is that the child process have to handle correctly the pipes destroying, if not it could got an error and close anyway. In this example the node child process seems to have no problem with this but it could be different with other scenario.

main.js

const { spawn } = require('child_process')

console.log('Start Main')

let child = spawn('node', ['child.js'], { detached: true })
child.unref() // With this the main process end after fully disconnect the child

child.stdout.on('data', data => {
  console.log(`Got data : ${data}`)
})

// In real case should be triggered just before the end of the main process
setTimeout(() => {
  console.log('Disconnect the child')

  child.stderr.unpipe()
  child.stderr.destroy()
  child.stdout.unpipe()
  child.stdout.destroy()
  child.stdin.end()
  child.stdin.destroy()
}, 5000)

child.js

console.log('Start Child')

setInterval(function() {
   process.stdout.write('hello from child')
}, 1000)

output

Start Main
Got data : Start Child

Got data : hello from child
Got data : hello from child
Got data : hello from child
Got data : hello from child
Disconnect the child

like image 52
Opsse Avatar answered Oct 27 '22 12:10

Opsse