Po rozpoczęciu odłącz proces potomny spawn

9

Proces potomny spawn rozpoczynam w ten sposób:

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

process.unref()

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

Kiedy zaczynam proces, muszę go trzymać, ponieważ chcę odczytać jego dane wyjściowe. Ale tuż przed zamknięciem procesu Node (rodzic) chcę odłączyć wszystkie nieukończone procesy potomne, aby działały w tle, ale jak mówi dokumentacja :

Podczas korzystania z opcji odłączonej w celu uruchomienia długotrwałego procesu, proces nie będzie działał w tle po wyjściu z rodzica, chyba że zostanie wyposażony w konfigurację stdio, która nie jest połączona z rodzicem.

Ale z opcją stdio: 'ignore'nie mogę odczytać, stdoutktóry jest problemem.

Próbowałem ręcznie zamknąć potoki przed zamknięciem procesu nadrzędnego, ale nie powiodło się:

// Trigger just before the main process end
process.stdin.end()
process.stderr.unpipe()
process.stdout.unpipe()
Opsse
źródło
1
Jestem trochę zdezorientowany, dlaczego spodziewałbyś się, że będziesz w stanie odczytać stdout / stderr procesu niezależnego od Node. Albo musisz przechwycić dane wyjściowe, ponieważ proces wykonuje zadania, które są częścią twojego programu (tylko działa równolegle), w którym to przypadku Węzeł powinien być rodzicem; lub uruchamiasz naprawdę niezależny program, w którym to przypadku jego standardowe wyjście nie stanowi problemu dla twojego programu Node i powinieneś zmusić je do udostępniania danych w sposób, który ma sens dla dwóch niezależnych programów (np. baza danych, monitor plików, serwer API , cokolwiek).
Mike „Pomax” Kamermans
Może nie byłem wystarczająco jasny, kiedy zaczynam proces, muszę go trzymać, ponieważ chcę odczytać jego wynik. Ale tuż przed zamknięciem procesu Node (rodzic) chcę odłączyć wszystkie nieukończone procesy potomne, aby działały w tle.
Opsse
Dlaczego nie mieć różnych procesów / programów i dzielić się danymi między nimi za pomocą pliku lub w inny sposób.
Ma'moun othman
To nie to, co robi fajka? Sugerujesz więc, aby samodzielnie obsługiwać komunikację między procesami?
Opsse
Ale dlaczego miałbyś odrywać ten proces? Albo robi coś, co służy Twojemu programowi, w takim przypadku twój program powinien poczekać, aż się skończy, lub powinien zasygnalizować procesowi, że skończył się czas i musi dokończyć to, co robi, ponieważ ma zamiar uzyskać SIGKILL - Zasadniczo : jaki jest rzeczywisty przypadek użycia? Ponieważ brzmi to jak główny kandydat na problem XY, w którym próbujesz coś zrobić, a myślałeś o tym, jak to zrobić, i pytasz o to, jak to zrobić, zamiast pytać o pierwotny problem
Mike „Pomax” Kamermans

Odpowiedzi:

1

Po wielu testach znalazłem przynajmniej jeden sposób na rozwiązanie tego problemu: zniszczenie całej rury przed wyjściem z głównego procesu.

Jednym z trudnych punktów jest to, że proces potomny musi poprawnie obsługiwać niszczenie rur, jeśli nie, może i tak otrzymać błąd i zamknąć się. W tym przykładzie proces potomny węzła wydaje się nie mieć z tym problemu, ale może być inny w przypadku innego scenariusza.

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)

wynik

Start Main
Got data: Start Child

Mam dane: cześć od dziecka
Mam dane: cześć od dziecka
Mam dane: cześć od dziecka
Mam dane: cześć od dziecka
Odłącz dziecko

Opsse
źródło