bgbash
bgbash
is a partial drop-in replacement for require('child_process').exec
specifically made for long-running applications.
npm i bgbash --save
Why?
Starting a child process using spawn
or exec
will create a new instance of ChildProcess
, open several streams and create a new system background process. This is very expensive if you do it often. bgbash
starts a single background process on the the first request, every future request will use that process's stdin
to execute commands. Reducing the startup and feedback time for subsequent calls.
Performance comparison
"echo hi" - 2000 runs on node-v10.12.0(darwin) | node.js | bgback | notes |
---|
startup | 10.98ms | 16.05ms | 46% slower - The startup is naturally slower as it does a little more. |
repeat response | 4.91ms | 1.96ms | 251% faster - But repeat calls are significantly faster, |
repeat user | 1.31ms | 0.95ms | 137% faster - with part of it coming from the reduced user execution time ... |
repeat system | 0.64ms | 0.04ms | 1457% faster - ... and a significantly reduced system execution time. |
rss | 37.9Mb (avg. 19.8Mb) | 9.9Mb (avg. 6.6Mb) | With a significantly lower rss memory allocation (which is stable even with more calls) |
heap total | 37.5Mb (avg. 21.4Mb) | 6Mb (avg. 3.2Mb) | The node.js version also fills up the heap a lot quicker to a avg. 32Mb use at 10000 execs while the bgback version needs around 20000 to get there. |
heap used | 19.5Mb (avg. 6.3Mb) | 4.1Mb (avg. 1.4Mb) | The difference in size can be attributed to the additional code loaded. This will slightly grow with number of calls (~20kb per 5000 calls). Reason is unclear but consistent for both the node.js and bgback version. |
c-memory inc. | 8.6Kb (avg. -201b) | 170b (avg. -7.8Kb) | The C++ memory can be negative as some initial c memory is cleared. |
Note: This data is compiled using the ./perf.js
script.
API compatibility
The API of exec
is implemented to be a reasonable (but not feature complete) drop-in replacement for node's native exec
.
const { exec } = require('bgbash')
const cmd = 'echo hi'
const opts = {
cwd: '.',
env: { KEY: 'value' }
timeout: 100,
encoding: 'utf8',
}
exec(cmd, opts, (error, stdout, stderr) => {
error
stdout
stderr
})
A notable incompatibility is that stderr
will be empty, even though output might exist, if no error occurs.
This is done for performance reasons.
Closing at shutdown
The background process will continue to run forever. If you want the process to close, you have to run close()
.
const { exec, close } = require('bgbash')
exec('echo hi')
close(
() => {
}
)
Promises API
Much like node js, bgbash
also comes with a Promise API that is available using either require('bgbash').promises
or require('bgbash/promises')
.
const { exec } = require('bgbash').promises
const opts = { }
const { stdout, stderr } = await exec('echo hi', opts)
try {
await exec('exit 1', opts)
} catch (error) {
}
License
MIT