mcollina / autocannon

fast HTTP/1.1 benchmarking tool written in Node.js
MIT License
7.83k stars 325 forks source link

Debugging connectivity issues | reqError === undefined #101

Closed anoff closed 7 years ago

anoff commented 7 years ago

I'm trying to set up autocannon and think I'm having some connectivity issues. Running against a local instance works fine. However if I target the remote machine I want to test, all requests seem to error. I suspect issues with proxy or broken SSL chains.

I couldn't figure out how to debug the request errors though. Is there a way to print each requests response/error message? It would help a lot to narrow down the problem.

const inst = autocannon({
  url: 'http://localhost:5010/api/v1/endpoint',
  connections: 10,
  pipelining: 20,
  duration: 10,
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: payload
}, (err, res) => {
    console.error(err);
    console.log(res);
});

let cnt = 0;
inst.on('reqError', e => console.log(`Request error (${cnt++}): ${e}`));

What happens is that I see a lot of those Request error logs but apparently there is no argument passed to it, so e===undefined

GlenTiki commented 7 years ago

'Broken ssl chains' leads me to ask the question: should you be using https?

anoff commented 7 years ago

@thekemkid if you're referring to the example code using http - copy&paste error. Questioning using HTTPS with a broken chain: Corporate proxy checks the packages content and therefore breaks the certificate chain. So it's a broken chain for me as a dev from within corporate network but our external customers have proper SSL.

GlenTiki commented 7 years ago

Fair enough, was just checking first. :)

What do get if you curl the endpoint you're testing?

GlenTiki commented 7 years ago

Also, for other purposes:

You can access the events the internal http client emits, using the setupClient property of the options. Check here: https://github.com/mcollina/autocannon#client-events (The internal error events aren't documented, that might be worth a PR)

You can use this to see if the errors are timeouts or connection errors, and if they're connection errors, get access to the error object passed to the socket that created it. Here's the snippet you need:

const inst = autocannon({
  url: 'http://localhost:5010/api/v1/endpoint',
  connections: 10,
  pipelining: 20,
  duration: 10,
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: payload
   setupClient: setupClientEventHandlers
}, (err, res) => {
    console.error(err);
    console.log(res);
});

let cnt = 0;
inst.on('reqError', e => console.log(`Request error (${cnt++}): ${e}`));

function setupClientEventHandlers (client) {
   client.on('connError', (error) => console.log('connection error', error))
   client.on('timeout', (error) => console.log('timeout'))
}
anoff commented 7 years ago

Thanks for the quick response. I'm planning to PR updated docs once I found all the required events. Have to wait to until monday to try that snippet though 😿

anoff commented 7 years ago

When curling the endpoint I get the expected response. The connError fires with a ENOTFOUND dns error.

~~It seems like autocannon is not aware of the $HTTP_PROXY environment variables available. The same error occurs on curl if i don't have any proxies set. I'll try to dig into the code but helpful for any hints :)~~

PS: I tried using it over HTTP (which is also served atm) to rule out SSL issues. HTTPS also fails for the same reason.

connection error { Error: getaddrinfo ENOTFOUND mydomain.com mydomain.com:80
    at errnoException (dns.js:28:10)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:76:26)
  code: 'ENOTFOUND',
  errno: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'mydomain.com',
  host: 'mydomain.com',
  port: 80 }

Edit: Seems to be setup with my machine as node -p 'dns.lookup("google.com", {family: 4}, console.log)' doesn't work either. Trying to figure out what went wrong here.

Edit2: Ok my Proxy (HTTP only) won't allow the DNS resolve to work 😩

GlenTiki commented 7 years ago

So, autocannon just uses a node tcp socket to connect to the server and a different http parser under the hood. Maybe try debugging with a node script to fetch what you need before benchmarking? Just try with request and let us know if that works/resolves

anoff commented 7 years ago

request works fine since it has support for proxies. However net and tls do not support proxies. Would it be of any use to try to use the native http module instead of net? I imagine that using the low-level network interfaces is one of the reasons that autocannon is able to achieve better performance than other node libraries.

mcollina commented 7 years ago

Sorry to jump on this, but are you trying to do http load testing through an HTTP proxy?

anoff commented 7 years ago

@mcollina Yes, at least while developing the test-suite.

mcollina commented 7 years ago

That is definitely not supported at the moment by autocannon, and adding the support might be difficult. However, the problem is that the error is not really forwarded to you and we should fix that.

You shouldn't really run autocannon (or any other benchmarking tool) against an HTTP proxy.

anoff commented 7 years ago

I understand that benchmarking through a proxy does not make sense. However I also don't want to deploy to the designated test runtime to set the thing up. I was planning on running it with non-benchmark parameters. But I'll just have to stub the autocannon behavior for development then.

Feel free to close the issue, I'll try to PR updated docs with the hints that @thekemkid gave me earlier for future reference. Or if you have any ideas how the error should be propagated I could try to do a code-PR