Détacher un processus enfant d'apparition après le démarrage

9

Je lance un processus enfant de réapparition de cette façon:

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

process.unref()

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

Lorsque je démarre le processus, je dois le garder attaché parce que je veux lire sa sortie. Mais juste avant de fermer mon processus Node (le parent), je veux détacher tous les processus enfants non terminés pour les faire fonctionner en arrière-plan, mais comme le dit la documentation :

Lorsque vous utilisez l'option détachée pour démarrer un processus de longue durée, le processus ne continuera pas à s'exécuter en arrière-plan après la sortie du parent, sauf s'il est fourni avec une configuration stdio qui n'est pas connectée au parent.

Mais avec l'option, stdio: 'ignore'je ne peux pas lire ce stdoutqui est un problème.

J'ai essayé de fermer manuellement les tuyaux avant de fermer le processus parent, mais il échoue:

// Trigger just before the main process end
process.stdin.end()
process.stderr.unpipe()
process.stdout.unpipe()
Opsse
la source
1
Je suis un peu confus pourquoi vous vous attendez à pouvoir lire stdout / stderr d'un processus indépendant de Node. Soit vous devez capturer la sortie, car le processus exécute des tâches qui font partie de votre programme (juste en parallèle), auquel cas Node doit être le parent; ou vous démarrez un programme vraiment indépendant, auquel cas sa sortie standard n'est pas la préoccupation de votre programme Node et vous devez leur faire partager des données d'une manière qui a du sens pour deux programmes indépendants (par exemple une base de données, un moniteur de fichiers, un serveur API , peu importe).
Mike 'Pomax' Kamermans
Peut-être que je n'étais pas assez clair, quand je démarre le processus, je dois le garder attaché parce que je veux lire sa sortie. Mais juste avant de fermer mon processus Node (le parent), je veux détacher tous les processus enfants non terminés pour les faire fonctionner en arrière-plan.
Opsse
Pourquoi ne pas avoir différents processus / programmes et partager des données entre eux en utilisant un fichier ou tout autre moyen.
ROOT
Ce n'est pas ce que fait une pipe? Vous proposez donc de gérer moi-même la communication entre les processus?
Opsse
Mais pourquoi détacheriez-vous le processus? Soit il fait quelque chose au service de votre programme, auquel cas votre programme devrait attendre qu'il soit terminé, soit il devrait signaler au processus qu'il est hors du temps et doit terminer ce qu'il fait parce qu'il est sur le point d'obtenir SIGKILL - Fondamentalement : quel est le cas d'utilisation réel? Parce que cela ressemble à un candidat de choix pour un problème XY où vous essayez de faire quelque chose, et vous avez pensé à un moyen de le faire, et vous vous interrogez sur cette façon de faire les choses au lieu de poser des questions sur le problème d'origine
Mike 'Pomax' Kamermans

Réponses:

1

Après de nombreux tests, j'ai trouvé au moins un moyen de résoudre ce problème: détruire tous les tuyaux avant de quitter le processus principal.

Un point délicat est que le processus enfant doit gérer correctement la destruction des tuyaux, sinon il pourrait avoir une erreur et se fermer de toute façon. Dans cet exemple, le processus enfant du nœud ne semble pas avoir de problème avec cela, mais il pourrait être différent avec un autre scénario.

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)

production

Start Main
Got data: Start Child

Obtenu des données: bonjour de l'enfant
Obtenu des données: bonjour de l'enfant
Obtenu des données: bonjour de l'enfant
Obtenu des données: bonjour de l'enfant
Déconnecter l'enfant

Opsse
la source