Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

--on-port #145

Merged
merged 26 commits into from
Aug 20, 2018
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5371e0e
Add --on-port flag to start once a process is running
goto-bus-stop Jul 18, 2018
aa590d2
Import URL constructor
goto-bus-stop Jul 18, 2018
f456348
Add --on-port test
goto-bus-stop Jul 18, 2018
936a9a2
Use `nitm`.
goto-bus-stop Jul 19, 2018
17e5c58
Update --on-port doc
goto-bus-stop Jul 20, 2018
a05fc8b
Accept hostless URL if --on-port is given.
goto-bus-stop Jul 20, 2018
50ac96e
Update readme.md with help.txt contents.
goto-bus-stop Jul 20, 2018
c930369
add debug line for travis bc this is passing locally
goto-bus-stop Jul 20, 2018
0f309ad
Revert "add debug line for travis bc this is passing locally"
goto-bus-stop Jul 20, 2018
efe1537
Fix "N requests" regex in --on-port test.
goto-bus-stop Jul 20, 2018
6b2025c
add another debug line for travis
goto-bus-stop Jul 20, 2018
ab1212b
Fix detectPort injection on windows (probably)
goto-bus-stop Aug 10, 2018
304826a
Exit if --on-port is used without async_hooks
goto-bus-stop Aug 10, 2018
06270f6
Revert "add another debug line for travis"
goto-bus-stop Aug 10, 2018
1bb1f33
Fix shutdown ENOTCONN error
goto-bus-stop Aug 10, 2018
dc0cf5b
Fix spawning child proc in test on windows
goto-bus-stop Aug 10, 2018
54be888
use path.join like other tests
goto-bus-stop Aug 10, 2018
851ece7
Use IPC socket instead of a pipe for windows friends
goto-bus-stop Aug 10, 2018
9ef4270
Avoid the half open stuff
goto-bus-stop Aug 10, 2018
f85b259
Update --on-port test to expect new percentiles output
goto-bus-stop Aug 15, 2018
98a67de
Update --on-port test to expect new percentiles output
goto-bus-stop Aug 15, 2018
0420249
injects → lib/preload like 0x
goto-bus-stop Aug 15, 2018
56fb442
NODE_OPTIONS is available in 8.0.0
goto-bus-stop Aug 15, 2018
a98b679
Remove nitm SIGINT workaround
goto-bus-stop Aug 17, 2018
515c5f9
Move socket setup to a function
goto-bus-stop Aug 17, 2018
0027720
Pass through existing $NODE_OPTIONS
goto-bus-stop Aug 17, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ Available options:
The amount of requests to make before exiting the benchmark. If set, duration is ignored.
-S/--socketPath
A path to a Unix Domain Socket or a Windows Named Pipe. A URL is still required in order to send the correct Host header and path.
--on-port
Start the command listed after -- on the command line. When it starts listening on a port,
start sending requests to that port. A URL is still required in order to send requests to
the correct path. The hostname can be omitted, `localhost` will be used by default.
-m/--method METHOD
The http method to use. default: 'GET'.
-t/--timeout NUM
Expand Down
46 changes: 43 additions & 3 deletions autocannon.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const minimist = require('minimist')
const fs = require('fs')
const path = require('path')
const URL = require('url').URL
const nitm = require('nitm')
const help = fs.readFileSync(path.join(__dirname, 'help.txt'), 'utf8')
const run = require('./lib/run')
const track = require('./lib/progressTracker')
Expand All @@ -23,7 +24,7 @@ module.exports.parseArguments = parseArguments

function parseArguments (argvs) {
const argv = minimist(argvs, {
boolean: ['json', 'n', 'help', 'renderLatencyTable', 'renderProgressBar', 'forever', 'idReplacement', 'excludeErrorStats'],
boolean: ['json', 'n', 'help', 'renderLatencyTable', 'renderProgressBar', 'forever', 'idReplacement', 'excludeErrorStats', 'onPort'],
alias: {
connections: 'c',
pipelining: 'p',
Expand All @@ -32,6 +33,7 @@ function parseArguments (argvs) {
amount: 'a',
json: 'j',
renderLatencyTable: ['l', 'latency'],
onPort: 'on-port',
method: 'm',
headers: ['H', 'header'],
body: 'b',
Expand Down Expand Up @@ -65,11 +67,16 @@ function parseArguments (argvs) {
method: 'GET',
idReplacement: false,
excludeErrorStats: false
}
},
'--': true
})

argv.url = argv._[0]

if (argv.onPort) {
argv.spawn = argv['--']
}

// support -n to disable the progress bar and results table
if (argv.n) {
argv.renderProgressBar = false
Expand Down Expand Up @@ -100,7 +107,12 @@ function parseArguments (argvs) {

// check that the URL is valid.
try {
new URL(argv.url) // eslint-disable-line no-new
// If --on-port is given, it's acceptable to not have a hostname
if (argv.onPort) {
new URL(argv.url, 'http://localhost') // eslint-disable-line no-new
} else {
new URL(argv.url) // eslint-disable-line no-new
}
} catch (err) {
console.error(err.message)
console.error('')
Expand Down Expand Up @@ -139,9 +151,37 @@ function start (argv) {
return
}

if (argv.onPort) {
const proc = nitm(
['-r', require.resolve('./lib/detectPort')],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use NODE_PATH instead, as this will fail on windows with usernames with spaces in them (which lots of people have there).

Move detectPort.js to another folder, fx ./injects and set process.env.NODE_PATH = path.join(__dirname, '/injects') and use ['-r', 'detectPort'] to work around that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took it from https://github.com/davidmarkclements/0x/blob/3611fc7f7c04ee741daeda33c972bb26cd7bdd0b/platform/v8.js#L34, so we should also change it there then. Does windows not support quoted arguments? 😱

argv.spawn,
{ stdio: ['ignore', 'inherit', 'inherit', 'pipe'] }
)

proc.stdio[3].once('data', (chunk) => {
const port = chunk.toString()
const url = new URL(argv.url, `http://localhost:${port}`).href
const opts = Object.assign({}, argv, {
onPort: false,
url: url
})
runTracker(opts, () => {
// `nitm` catches the SIGINT so we write it to a file descriptor
// instead of doing proc.kill()
proc.stdio[3].write('SIGINT')
proc.stdio[3].end()
})
})
} else {
runTracker(argv)
}
}

function runTracker (argv, ondone) {
const tracker = run(argv)

tracker.on('done', (result) => {
if (ondone) ondone()
if (argv.json) {
console.log(JSON.stringify(result))
}
Expand Down
4 changes: 4 additions & 0 deletions help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Available options:
The amount of requests to make before exiting the benchmark. If set, duration is ignored.
-S/--socketPath
A path to a Unix Domain Socket or a Windows Named Pipe. A URL is still required in order to send the correct Host header and path.
--on-port
Start the command listed after -- on the command line. When it starts listening on a port,
start sending requests to that port. A URL is still required in order to send requests to
the correct path. The hostname can be omitted, `localhost` will be used by default.
-m/--method METHOD
The http method to use. default: 'GET'.
-t/--timeout NUM
Expand Down
17 changes: 17 additions & 0 deletions lib/detectPort.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict'

const onListen = require('on-net-listen')
const fs = require('fs')

onListen(function (addr) {
this.destroy()
const port = Buffer.from(addr.port + '')
fs.writeSync(3, port, 0, port.length)
})

// `nitm` catches the SIGINT so we write it to a file descriptor instead
const stream = fs.createReadStream('/', { fd: 3 })
process.on('exit', () => stream.close())
stream.once('data', (chunk) => {
if (chunk.toString() === 'SIGINT') process.exit(0)
})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should unref the stream here? Just incase the server closes gracefully and we don't wanna keep it open.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm actually not sure how to do this, fs.ReadStream doesn't have an unref(). autocannon will send the SIGINT when it's done anyway so currently the process just keeps running for those additional seconds. Ideally the child process would exit when the server closes and autocannon would also stop, I guess?

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
"http-parser-js": "^0.4.13",
"hyperid": "^1.4.1",
"minimist": "^1.2.0",
"nitm": "^1.0.2",
"on-net-listen": "^1.1.1",
"pretty-bytes": "^5.1.0",
"progress": "^2.0.0",
"reinterval": "^1.1.0",
Expand Down
48 changes: 48 additions & 0 deletions test/onPort.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use strict'

const t = require('tap')
const spawn = require('child_process').spawn
const split = require('split2')
const autocannon = require.resolve('../autocannon')
const target = require.resolve('./targetProcess')

const lines = [
/Running 1s test @ .*$/,
/10 connections.*$/,
/$/,
/Stat.*Avg.*Stdev.*Max.*$/,
/Latency \(ms\).*$/,
/Req\/Sec.*$/,
/Bytes\/Sec.*$/,
/$/,
// Ensure that there are more than 0 successful requests
/[1-9]\d*.* requests in \d+s, .* read/
]

t.plan(lines.length * 2)

const child = spawn(autocannon, [
'-c', '10',
'-d', '1',
'--on-port', '/',
'--', 'node', target
], {
cwd: __dirname,
env: process.env,
stdio: ['ignore', 'pipe', 'pipe'],
detached: false
})

t.tearDown(() => {
child.kill()
})

child
.stderr
.pipe(split())
.on('data', (line) => {
const regexp = lines.shift()
console.error(line)
t.ok(regexp, 'we are expecting this line')
t.ok(regexp.test(line), 'line matches ' + regexp)
})
3 changes: 3 additions & 0 deletions test/targetProcess.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const server = require('./helper').startServer()

server.ref()