Open Funecio-Agrante opened 1 month ago
@nodejs/http
I managed to fix the part about not triggering errors. I was mixing Promise error handling that uses .catch
blocks with async/await error handling that uses try...catch.
I can also confirm that somewhere between node v18 and the current node v22 there was a bug fix important for this situation. After cleaning up the catch logic with node v18 the code was still exiting without triggering any catch.
I still get an error every 10k requests, but now I know what the error is and I can handle it. I would still like to know why this happens. Perhaps it's a bug?
The error is
Error: socket hang up at ClientRequest.
(file:///home/user/path/to/file/) at ClientRequest.emit (node:events:520:28) at TLSSocket.socketCloseListener (node:_http_client:475:11) at TLSSocket.emit (node:events:532:35) at node:net:338:12 at done (node:_tls_wrap:659:7) at TLSWrap.close (node:_tls_wrap:665:7) at closeSocketHandle (node:net:336:18) at Socket._destroy (node:net:826:7) at _destroy (node:internal/streams/destroy:122:10)
Some servers kills a socket after X amount of request. This might be your case.
Node.js Version
v22.2.0
NPM Version
10.7.0
Operating System
Linux 5.15.0-107-generic x86_64 (Ubuntu 22.04.4 LTS)
Subsystem
events, http, https
Description
I'm trying to setup a local HTTP proxy to be able to throttle HTTPS requests from several concurrent processes to the same remote server. The setup is working.
It uses a custom agent to establish a connection through the proxy. The issue is that the agent's socket closes shortly after the execution starts, as it tries to execute an https.get and
it doesn't raise any errors I could catch
with the agent option
keepAlive: true
, it stops execution exactly after 10000 requests, ie, as the 10001st is being executedwith the agent option
keepAlive: false
, it stops execution somewhere in the range of 60k-100k requestsI did a bunch of testing and I can offer a few data points:
the 'close' event emitter is always triggered, but a
reject
statement within the event handler doesn't do anything. On the other hand, if I force a timeout after the 10k request (and before the process exits without errors), areject
statement within the timeout event handler does get executed as expectedNode does show a warning message, but again, no errors
https.get
(without proxy) doesn't stop after 10k requests, so it doesn't seem to be any problem without the proxy setupThe server code is based on this example https://scraperjs.wordpress.com/2013/10/22/a-simple-https-tunneling-proxy-in-node-js/
The client code is based on this example
https://antoinevastel.com/nodejs/2022/02/26/nodejs-optimized-https-proxy-no-dependencies.html
Minimal Reproduction
You can use this code to start the server on a separate console window
You can use this code to make the requests on another console window. I provide a few different public endpoints that generate JSON responses. You can easily switch in the code.
The bulk of the logic is in a class you can copy from this Gist https://gist.github.com/Funecio-Agrante/a01f367cff6a0acbaf1ce90558abf5bd
If you lower the timeout in the constructor to less than 20000, you will see that the timeout event emitter gets triggered and the
reject
statement inside is executed; whereas the close event emitter is executed in the inverse situation and thereject
statement there doesn't produce any effect.It should take about 20 minutes to reach 10k requests and reproduce the issue.
Output
The script stops execution without errors, only a warning (that didn't exist in node v18). By printing to console within event emitter handlers, I get this information:
Before You Submit