Skip to content

Commit fe33b80

Browse files
starkwangfengmk2
authored andcommitted
feat: Add reusedSocket property on client request (#82)
1 parent 77ba744 commit fe33b80

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

README.md

+24
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,30 @@ setTimeout(() => {
165165
}, 2000);
166166
```
167167

168+
### Support `req.reusedSocket`
169+
170+
This agent implements the `req.reusedSocket` to determine whether a request is send through a reused socket.
171+
172+
When server closes connection at unfortunate time ([keep-alive race](https://code-examples.net/en/q/28a8069)), the http client will throw a `ECONNRESET` error. Under this circumstance, `req.reusedSocket` is useful when we want to retry the request automatically.
173+
174+
```js
175+
const http = require('http');
176+
const Agent = require('agentkeepalive');
177+
const agent = new Agent();
178+
179+
const req = http
180+
.get('http://localhost:3000', { agent }, (res) => {
181+
// ...
182+
})
183+
.on('error', (err) => {
184+
if (req.reusedSocket && err.code === 'ECONNRESET') {
185+
// retry the request or anything else...
186+
}
187+
})
188+
```
189+
190+
This behavior is consistent with Node.js core. But through `agentkeepalive`, you can use this feature in older Node.js version.
191+
168192
## [Benchmark](https://github.com/node-modules/agentkeepalive/tree/master/benchmark)
169193

170194
run the benchmark:

lib/agent.js

+2
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ class Agent extends OriginalAgent {
140140
// reuseSocket(socket, req)
141141
super.reuseSocket(...args);
142142
const socket = args[0];
143+
const req = args[1];
144+
req.reusedSocket = true;
143145
const agentTimeout = this.options.timeout;
144146
if (getSocketTimeout(socket) !== agentTimeout) {
145147
// reset timeout before use

test/agent.test.js

+37
Original file line numberDiff line numberDiff line change
@@ -1495,6 +1495,43 @@ describe('test/agent.test.js', () => {
14951495
assert(Object.keys(agentkeepalive.sockets).length === 1);
14961496
});
14971497

1498+
it('should set req.reusedSocket to true when reuse socket', done => {
1499+
const agent = new Agent({
1500+
keepAlive: true,
1501+
});
1502+
1503+
// First request
1504+
const req1 = http.get({
1505+
port,
1506+
path: '/',
1507+
agent,
1508+
}, res => {
1509+
assert(res.statusCode === 200);
1510+
res.on('data', () => {});
1511+
res.on('end', () => {
1512+
setTimeout(() => {
1513+
// Second request
1514+
const req2 = http.get({
1515+
port,
1516+
path: '/',
1517+
agent,
1518+
}, res => {
1519+
assert(res.statusCode === 200);
1520+
res.on('data', () => {});
1521+
res.on('end', () => {
1522+
done();
1523+
});
1524+
});
1525+
// Second request reuses the socket
1526+
assert(req2.reusedSocket);
1527+
}, 10);
1528+
});
1529+
});
1530+
1531+
// First request doesn't reuse the socket
1532+
assert(!req1.reusedSocket);
1533+
});
1534+
14981535
describe('request timeout > agent timeout', () => {
14991536
it('should use request timeout', done => {
15001537
const agent = new Agent({

0 commit comments

Comments
 (0)