129 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# foreground-child
 | 
						|
 | 
						|
Run a child as if it's the foreground process. Give it stdio. Exit
 | 
						|
when it exits.
 | 
						|
 | 
						|
Mostly this module is here to support some use cases around
 | 
						|
wrapping child processes for test coverage and such. But it's
 | 
						|
also generally useful any time you want one program to execute
 | 
						|
another as if it's the "main" process, for example, if a program
 | 
						|
takes a `--cmd` argument to execute in some way.
 | 
						|
 | 
						|
## USAGE
 | 
						|
 | 
						|
```js
 | 
						|
import { foregroundChild } from 'foreground-child'
 | 
						|
// hybrid module, this also works:
 | 
						|
// const { foregroundChild } = require('foreground-child')
 | 
						|
 | 
						|
// cats out this file
 | 
						|
const child = foregroundChild('cat', [__filename])
 | 
						|
 | 
						|
// At this point, it's best to just do nothing else.
 | 
						|
// return or whatever.
 | 
						|
// If the child gets a signal, or just exits, then this
 | 
						|
// parent process will exit in the same way.
 | 
						|
```
 | 
						|
 | 
						|
You can provide custom spawn options by passing an object after
 | 
						|
the program and arguments:
 | 
						|
 | 
						|
```js
 | 
						|
const child = foregroundChild(`cat ${__filename}`, { shell: true })
 | 
						|
```
 | 
						|
 | 
						|
A callback can optionally be provided, if you want to perform an
 | 
						|
action before your foreground-child exits:
 | 
						|
 | 
						|
```js
 | 
						|
const child = foregroundChild('cat', [__filename], spawnOptions, () => {
 | 
						|
  doSomeActions()
 | 
						|
})
 | 
						|
```
 | 
						|
 | 
						|
The callback can return a Promise in order to perform
 | 
						|
asynchronous actions. If the callback does not return a promise,
 | 
						|
then it must complete its actions within a single JavaScript
 | 
						|
tick.
 | 
						|
 | 
						|
```js
 | 
						|
const child = foregroundChild('cat', [__filename], async () => {
 | 
						|
  await doSomeAsyncActions()
 | 
						|
})
 | 
						|
```
 | 
						|
 | 
						|
If the callback throws or rejects, then it will be unhandled, and
 | 
						|
node will exit in error.
 | 
						|
 | 
						|
If the callback returns a string value, then that will be used as
 | 
						|
the signal to exit the parent process. If it returns a number,
 | 
						|
then that number will be used as the parent exit status code. If
 | 
						|
it returns boolean `false`, then the parent process will not be
 | 
						|
terminated. If it returns `undefined`, then it will exit with the
 | 
						|
same signal/code as the child process.
 | 
						|
 | 
						|
## Caveats
 | 
						|
 | 
						|
The "normal" standard IO file descriptors (0, 1, and 2 for stdin,
 | 
						|
stdout, and stderr respectively) are shared with the child process.
 | 
						|
Additionally, if there is an IPC channel set up in the parent, then
 | 
						|
messages are proxied to the child on file descriptor 3.
 | 
						|
 | 
						|
In Node, it's possible to also map arbitrary file descriptors
 | 
						|
into a child process. In these cases, foreground-child will not
 | 
						|
map the file descriptors into the child. If file descriptors 0,
 | 
						|
1, or 2 are used for the IPC channel, then strange behavior may
 | 
						|
happen (like printing IPC messages to stderr, for example).
 | 
						|
 | 
						|
Note that a SIGKILL will always kill the parent process, but
 | 
						|
will not proxy the signal to the child process, because SIGKILL
 | 
						|
cannot be caught. In order to address this, a special "watchdog"
 | 
						|
child process is spawned which will send a SIGKILL to the child
 | 
						|
process if it does not terminate within half a second after the
 | 
						|
watchdog receives a SIGHUP due to its parent terminating.
 | 
						|
 | 
						|
On Windows, issuing a `process.kill(process.pid, signal)` with a
 | 
						|
fatal termination signal may cause the process to exit with a `1`
 | 
						|
status code rather than reporting the signal properly. This
 | 
						|
module tries to do the right thing, but on Windows systems, you
 | 
						|
may see that incorrect result. There is as far as I'm aware no
 | 
						|
workaround for this.
 | 
						|
 | 
						|
## util: `foreground-child/proxy-signals`
 | 
						|
 | 
						|
If you just want to proxy the signals to a child process that the
 | 
						|
main process receives, you can use the `proxy-signals` export
 | 
						|
from this package.
 | 
						|
 | 
						|
```js
 | 
						|
import { proxySignals } from 'foreground-child/proxy-signals'
 | 
						|
 | 
						|
const childProcess = spawn('command', ['some', 'args'])
 | 
						|
proxySignals(childProcess)
 | 
						|
```
 | 
						|
 | 
						|
Now, any fatal signal received by the current process will be
 | 
						|
proxied to the child process.
 | 
						|
 | 
						|
It doesn't go in the other direction; ie, signals sent to the
 | 
						|
child process will not affect the parent. For that, listen to the
 | 
						|
child `exit` or `close` events, and handle them appropriately.
 | 
						|
 | 
						|
## util: `foreground-child/watchdog`
 | 
						|
 | 
						|
If you are spawning a child process, and want to ensure that it
 | 
						|
isn't left dangling if the parent process exits, you can use the
 | 
						|
watchdog utility exported by this module.
 | 
						|
 | 
						|
```js
 | 
						|
import { watchdog } from 'foreground-child/watchdog'
 | 
						|
 | 
						|
const childProcess = spawn('command', ['some', 'args'])
 | 
						|
const watchdogProcess = watchdog(childProcess)
 | 
						|
 | 
						|
// watchdogProcess is a reference to the process monitoring the
 | 
						|
// parent and child. There's usually no reason to do anything
 | 
						|
// with it, as it's silent and will terminate
 | 
						|
// automatically when it's no longer needed.
 | 
						|
```
 |