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

--on-port #145

merged 26 commits into from
Aug 20, 2018

Conversation

goto-bus-stop
Copy link
Contributor

@goto-bus-stop goto-bus-stop commented Jul 18, 2018

Do autocannon --on-port /api/expensive-route -- node server.js to cannonise a script once it's booted up.

This works by delaying the run() call until the script has started listening on a port, and then starting autocannon targeting http://localhost:${THAT_PORT}/api/expensive-route. Once over the script gets a SIGINT like in 0x.

There are a few things I'm not certain about:

  • 0x implements the child process spawning inside its Node API, this patch only implements it in the CLI. This is quite a bit easier to do because all of the run() setup doesn't have to be async this way, but maybe there is a use case for this functionality in the Node API too?
  • I'm just assuming targeting 'localhost:PORT' is the right thing to do, but maybe it's not? I'm not sure what else it could be, and users can specify a full URL if they need rather than just a path, so it shouldn't be a problem in most cases.
  • Should probably actually use nitm instead

Same URL disclaimer as #147:

It uses the URL API which was backported to Node 6.13.0, if lower
versions of Node 6 should be supported I can change it to use
url.parse and url.format instead.

@goto-bus-stop goto-bus-stop changed the title --on-port [WIP-ish] --on-port Jul 18, 2018
@mcollina
Copy link
Owner

0x implements the child process spawning inside its Node API, this patch only implements it in the CLI. This is quite a bit easier to do because all of the run() setup doesn't have to be async this way, but maybe there is a use case for this functionality in the Node API too?

I think this is only a CLI feature. However, I'm good with placing it in exposing it as a reusable function, similar to what we do for track: https://github.com/mcollina/autocannon/blob/master/autocannon.js#L13. I don't think this should go into run.

I'm just assuming targeting 'localhost:PORT' is the right thing to do, but maybe it's not? I'm not sure what else it could be, and users can specify a full URL if they need rather than just a path, so it shouldn't be a problem in most cases.

That's a safe assumption, yes.

Should probably actually use nitm instead

Go for it!

@mcollina
Copy link
Owner

(CI is failing)

help.txt Outdated
@@ -14,6 +14,8 @@ 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 PATH
Start the command listed after -- on the command line. When it starts listening on a port, start sending requests to that port with the given URL path.
Copy link
Owner

Choose a reason for hiding this comment

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

We might want to move PATH out from this option. See #146.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah when i wrote that line my understanding of how it would work was wrong. it's a boolean flag in the code and PATH is just the URL. will update 👍

@goto-bus-stop
Copy link
Contributor Author

Hmm looking at the CI failures I would guess that latency.average ends up at 0 so the t.ok() check fails. I'll change it to t.type

@mcollina
Copy link
Owner

Can you please update the docs as well?

autocannon.js Outdated
@@ -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? 😱

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?

@mafintosh
Copy link

Looks good other than my comments 👍

@goto-bus-stop goto-bus-stop changed the title [WIP-ish] --on-port --on-port Aug 10, 2018
@goto-bus-stop
Copy link
Contributor Author

goto-bus-stop commented Aug 10, 2018

Oh, on-net-listen needs async_hooks, so this actually can't support Node 6 at all. Added a check for that too. The other CI failures are fixed by #144

e; Node 8:

events.js:183
      throw er; // Unhandled 'error' event
      ^
Error: shutdown ENOTCONN
    at _errnoException (util.js:992:11)
    at Socket.onSocketFinish (net.js:307:25)
    at emitNone (events.js:106:13)
    at Socket.emit (events.js:208:7)
    at finishMaybe (_stream_writable.js:614:14)
    at afterWrite (_stream_writable.js:465:3)
    at _combinedTickCallback (internal/process/next_tick.js:144:20)
    at process._tickCallback (internal/process/next_tick.js:180:9)

checking

e2; nodejs/node#13542

e3; ok, now the only remaining Travis failure is one fixed by #144 :P waiting for appveyor

@goto-bus-stop
Copy link
Contributor Author

@mafintosh oh the published nitm version does not have windows support yet. could you publish a new version? git master seems to work (it maybe loses the extra fd that's used for pseudo SIGINTs, as fs.writeSync(3) will throw in the child process, but need to look into that more closely first)

@mafintosh
Copy link

@goto-bus-stop oops, sorry about that. just published.

@goto-bus-stop
Copy link
Contributor Author

merci merci!

it seems like on windows there is no guarantee that the additional pipe is opened at fd=3: nodejs/node#14046 (comment)

prolly need to use a temp socket instead

@mafintosh
Copy link

@goto-bus-stop interesting about the fd stuff. we acutally just use fd 3 in the other modules and it seems to work quite well on windows (maybe just by chance!). Would be good to put these pseudo signals in a module also so we can test it independently etc

@goto-bus-stop
Copy link
Contributor Author

goto-bus-stop commented Aug 10, 2018 via email

@mafintosh
Copy link

@goto-bus-stop really? it's works for me consistently on windows. are you sure you are using the latest version of 0x?

@goto-bus-stop
Copy link
Contributor Author

goto-bus-stop commented Aug 10, 2018 via email

@goto-bus-stop
Copy link
Contributor Author

goto-bus-stop commented Aug 15, 2018

omg, the onPort test works when run as .\node_modules\.bin\tap test\onPort.test.js, but times out when run through npm test… 🤕

e; node.cmd is not started by spawnwrap.cmd when run from an npm script… 🤔
e; running with npm defines several differently cased $PATH environment variables. that may be an issue?
e; yes that's it :)
e; will be fixed in npm 6.4: npm/npm-lifecycle#22

@goto-bus-stop
Copy link
Contributor Author

goto-bus-stop commented Aug 17, 2018

After discussing with @mafintosh i removed nitm in favour of using NODE_OPTIONS, which is supported in all versions with async_hooks. on-net-listen requires async_hooks, so it was already required for --on-port.

Technically it's possible now to drop the socket stuff and just use fd 3 like 0x does, but I'm not entirely sure if fd 3 is really guaranteed or if it just usually coincidentally ends up working, so the socket way may still be more reliable...

I think this is ready, but I merged #144 into this to fix flaky tests on this branch which ruins the diff view, so it would be easiest if #144 was merged to master first and this was PR rebased.

@mafintosh
Copy link

LGTM, great work @goto-bus-stop

@mcollina mcollina merged commit 57ce004 into mcollina:master Aug 20, 2018
@mcollina
Copy link
Owner

Great work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants