HTTP Keep-alive, "socket hang up" ECONNERR on a long-running second request
Problem
Describe the bug On keep-alive connections, if a timeout value is given to the first request but not on subsequent requests, the subsequent requests will eventually throw a "socket hang up" error. To Reproduce [code block] Code snippet _No response_ Expected behavior 1. "socket hang up" is misleading because it indicates the server closed the connection (in this bug the opposite is true) 2. One would not expect that a timeout would keep running after a request has completed. This is a (quite major IMO) footgun. Axios Version 0.22.0 - 1.6.2 Adapter Version HTTP Browser _No response_ Browser Version _No response_ Node.js Version 20.9.0 OS OSX 14 Additional Library Versions _No response_ Additional context/Screenshots <img width="1456" alt="tcpdump" src="https://github.com/axios/axios/assets/100387231/a64c6544-4551-46ad-bb3e-1d9a6e9102b6">
Unverified for your environment
Select your OS to check compatibility.
1 Fix
Implement Timeout Reset for Keep-Alive Connections in Axios
The 'socket hang up' error occurs because the timeout set for the first request continues to affect subsequent requests on the same keep-alive connection. When the first request times out, it closes the socket, leading to the misleading error message. This happens because Axios does not reset the timeout for subsequent requests on the same connection, causing them to hang if the initial timeout is reached.
Awaiting Verification
Be the first to verify this fix
- 1
Update Axios Configuration
Modify the Axios instance to include a timeout reset mechanism for keep-alive connections. This ensures that each request can have its own timeout configuration, preventing the timeout from affecting subsequent requests.
javascriptconst axios = require('axios'); const axiosInstance = axios.create({ timeout: 10000, // Set a default timeout for requests httpAgent: new http.Agent({ keepAlive: true, timeout: 10000 }) // Ensure keep-alive with individual timeouts }); - 2
Set Individual Timeouts for Requests
When making requests, explicitly set the timeout for each request to ensure that they do not inherit the timeout from the initial request. This prevents the socket from hanging due to timeout issues.
javascriptaxiosInstance.get('/api/endpoint', { timeout: 5000 }) // Set a specific timeout for this request .then(response => console.log(response.data)) .catch(error => console.error('Error:', error)); - 3
Test Keep-Alive Behavior
Run tests to ensure that multiple requests can be made on the same keep-alive connection without encountering the 'socket hang up' error. Verify that each request's timeout is respected independently.
javascript// Example test const testRequests = async () => { await axiosInstance.get('/api/endpoint1', { timeout: 5000 }); await axiosInstance.get('/api/endpoint2', { timeout: 5000 }); }; testRequests(); - 4
Monitor Connection Behavior
Use monitoring tools or logging to observe the connection behavior and ensure that sockets remain open as expected during multiple requests. Check for any unexpected closures or errors.
javascriptconst tcpDump = require('tcpdump'); tcpDump.start(); // Start monitoring TCP connections
Validation
Confirm that subsequent requests do not throw a 'socket hang up' error and that each request respects its own timeout. Monitor the connections to ensure they remain active and functional during multiple requests.
Sign in to verify this fix
Environment
Submitted by
Alex Chen
2450 rep