agentkeepalive
Advanced tools
Comparing version 2.2.0 to 3.0.0
3.0.0 / 2016-12-20 | ||
================== | ||
* fix: emit agent socket close event | ||
* test: add remove excess calls to removeSocket | ||
* test: use egg-ci | ||
* test: refactor test with eslint rules | ||
* feat: merge _http_agent.js from 7.2.1 | ||
2.2.0 / 2016-06-26 | ||
@@ -3,0 +12,0 @@ ================== |
@@ -0,2 +1,4 @@ | ||
'use strict'; | ||
module.exports = require('./lib/agent'); | ||
module.exports.HttpsAgent = require('./lib/https_agent'); |
@@ -22,10 +22,10 @@ // Copyright Joyent, Inc. and other Node contributors. | ||
// copy from https://github.com/nodejs/node/blob/v4.x/lib/_http_agent.js | ||
// patch from https://github.com/nodejs/node/blob/v7.2.1/lib/_http_agent.js | ||
'use strict'; | ||
var net = require('net'); | ||
var util = require('util'); | ||
var EventEmitter = require('events').EventEmitter; | ||
var debug = require('./utils').debug; | ||
const net = require('net'); | ||
const util = require('util'); | ||
const EventEmitter = require('events'); | ||
const debug = util.debuglog('http'); | ||
@@ -64,9 +64,11 @@ // New Agent code. | ||
self.keepAlive = self.options.keepAlive || false; | ||
self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets; | ||
self.maxFreeSockets = self.options.maxFreeSockets || 256; | ||
// [patch start] | ||
// free keep-alive socket timeout. By default free socket do not have a timeout. | ||
// keepAliveTimeout should be rename to `freeSocketKeepAliveTimeout` | ||
self.keepAliveTimeout = self.options.keepAliveTimeout || 0; | ||
self.freeSocketKeepAliveTimeout = self.options.freeSocketKeepAliveTimeout || 0; | ||
// working socket timeout. By default working socket do not have a timeout. | ||
self.timeout = self.options.timeout || 0; | ||
self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets; | ||
self.maxFreeSockets = self.options.maxFreeSockets || 256; | ||
// [patch end] | ||
@@ -77,4 +79,7 @@ self.on('free', function(socket, options) { | ||
if (!socket.destroyed && | ||
if (socket.writable && | ||
self.requests[name] && self.requests[name].length) { | ||
// [patch start] | ||
debug('continue handle next request'); | ||
// [patch end] | ||
self.requests[name].shift().onSocket(socket); | ||
@@ -85,3 +90,2 @@ if (self.requests[name].length === 0) { | ||
} | ||
debug('continue handle next request'); | ||
} else { | ||
@@ -93,4 +97,4 @@ // If there are no pending requests, then put it in | ||
req.shouldKeepAlive && | ||
!socket.destroyed && | ||
self.options.keepAlive) { | ||
socket.writable && | ||
self.keepAlive) { | ||
var freeSockets = self.freeSockets[name]; | ||
@@ -101,6 +105,4 @@ var freeLen = freeSockets ? freeSockets.length : 0; | ||
count += self.sockets[name].length; | ||
// console.log(count, freeLen, self.maxSockets, self.maxFreeSockets) | ||
if (count > self.maxSockets || freeLen >= self.maxFreeSockets) { | ||
// console.log('hit max sockets', count, freeLen, self.maxSockets, self.maxFreeSockets); | ||
self.removeSocket(socket, options); | ||
socket.destroy(); | ||
@@ -111,3 +113,3 @@ } else { | ||
socket.setKeepAlive(true, self.keepAliveMsecs); | ||
socket.unref && socket.unref(); | ||
socket.unref(); | ||
socket._httpMessage = null; | ||
@@ -117,2 +119,3 @@ self.removeSocket(socket, options); | ||
// [patch start] | ||
// Add a default error handler to avoid Unhandled 'error' event throw on idle socket | ||
@@ -124,8 +127,7 @@ // https://github.com/node-modules/agentkeepalive/issues/25 | ||
} | ||
// set free keepalive timer | ||
socket.setTimeout(self.keepAliveTimeout); | ||
socket.setTimeout(self.freeSocketKeepAliveTimeout); | ||
// [patch end] | ||
} | ||
} else { | ||
self.removeSocket(socket, options); | ||
socket.destroy(); | ||
@@ -140,2 +142,3 @@ } | ||
// [patch start] | ||
function freeSocketErrorListener(err) { | ||
@@ -147,2 +150,3 @@ var socket = this; | ||
} | ||
// [patch end] | ||
@@ -154,22 +158,23 @@ Agent.defaultMaxSockets = Infinity; | ||
// Get the key for a given set of request options | ||
Agent.prototype.getName = function(options) { | ||
var name = ''; | ||
Agent.prototype.getName = function getName(options) { | ||
var name = options.host || 'localhost'; | ||
if (options.host) | ||
name += options.host; | ||
else | ||
name += 'localhost'; | ||
name += ':'; | ||
if (options.port) | ||
name += options.port; | ||
name += ':'; | ||
if (options.localAddress) | ||
name += options.localAddress; | ||
name += ':'; | ||
// Pacify parallel/test-http-agent-getname by only appending | ||
// the ':' when options.family is set. | ||
if (options.family === 4 || options.family === 6) | ||
name += ':' + options.family; | ||
return name; | ||
}; | ||
Agent.prototype.addRequest = function(req, options) { | ||
// Legacy API: addRequest(req, host, port, path) | ||
Agent.prototype.addRequest = function addRequest(req, options) { | ||
// Legacy API: addRequest(req, host, port, localAddress) | ||
if (typeof options === 'string') { | ||
@@ -179,3 +184,3 @@ options = { | ||
port: arguments[2], | ||
path: arguments[3] | ||
localAddress: arguments[3] | ||
}; | ||
@@ -187,2 +192,10 @@ } | ||
if (!options.servername) { | ||
options.servername = options.host; | ||
const hostHeader = req.getHeader('host'); | ||
if (hostHeader) { | ||
options.servername = hostHeader.replace(/:.*$/, ''); | ||
} | ||
} | ||
var name = this.getName(options); | ||
@@ -201,6 +214,8 @@ if (!this.sockets[name]) { | ||
// [patch start] | ||
// remove free socket error event handler | ||
socket.removeListener('error', freeSocketErrorListener); | ||
// restart the default timer | ||
socket.setTimeout(this.timeout); | ||
// [patch end] | ||
@@ -211,3 +226,3 @@ // don't leak | ||
socket.ref && socket.ref(); | ||
socket.ref(); | ||
req.onSocket(socket); | ||
@@ -218,3 +233,11 @@ this.sockets[name].push(socket); | ||
// If we are under maxSockets create a new one. | ||
req.onSocket(this.createSocket(req, options)); | ||
this.createSocket(req, options, function(err, newSocket) { | ||
if (err) { | ||
process.nextTick(function() { | ||
req.emit('error', err); | ||
}); | ||
return; | ||
} | ||
req.onSocket(newSocket); | ||
}); | ||
} else { | ||
@@ -230,3 +253,3 @@ debug('wait for socket'); | ||
Agent.prototype.createSocket = function(req, options) { | ||
Agent.prototype.createSocket = function createSocket(req, options, cb) { | ||
var self = this; | ||
@@ -238,7 +261,5 @@ options = util._extend({}, options); | ||
options.servername = options.host; | ||
if (req) { | ||
var hostHeader = req.getHeader('host'); | ||
if (hostHeader) { | ||
options.servername = hostHeader.replace(/:.*$/, ''); | ||
} | ||
const hostHeader = req.getHeader('host'); | ||
if (hostHeader) { | ||
options.servername = hostHeader.replace(/:.*$/, ''); | ||
} | ||
@@ -248,67 +269,81 @@ } | ||
var name = self.getName(options); | ||
options._agentKey = name; | ||
debug('createConnection', name, options); | ||
options.encoding = null; | ||
var s = self.createConnection(options); | ||
if (!self.sockets[name]) { | ||
self.sockets[name] = []; | ||
} | ||
this.sockets[name].push(s); | ||
debug('sockets', name, this.sockets[name].length); | ||
var called = false; | ||
const newSocket = self.createConnection(options, oncreate); | ||
if (newSocket) | ||
oncreate(null, newSocket); | ||
function oncreate(err, s) { | ||
if (called) | ||
return; | ||
called = true; | ||
if (err) | ||
return cb(err); | ||
if (!self.sockets[name]) { | ||
self.sockets[name] = []; | ||
} | ||
self.sockets[name].push(s); | ||
debug('sockets', name, self.sockets[name].length); | ||
function onFree() { | ||
self.emit('free', s, options); | ||
} | ||
s.on('free', onFree); | ||
function onFree() { | ||
self.emit('free', s, options); | ||
} | ||
s.on('free', onFree); | ||
function onClose(err) { | ||
debug('CLIENT socket onClose'); | ||
// fix: socket.destroyed always be undefined on 0.10.x | ||
if (typeof s.destroyed !== 'boolean') { | ||
s.destroyed = true; | ||
function onClose(err) { | ||
debug('CLIENT socket onClose'); | ||
// This is the only place where sockets get removed from the Agent. | ||
// If you want to remove a socket from the pool, just close it. | ||
// All socket errors end in a close event anyway. | ||
self.removeSocket(s, options); | ||
// [patch start] | ||
self.emit('close'); | ||
// [patch end] | ||
} | ||
s.on('close', onClose); | ||
// This is the only place where sockets get removed from the Agent. | ||
// If you want to remove a socket from the pool, just close it. | ||
// All socket errors end in a close event anyway. | ||
self.removeSocket(s, options); | ||
self.emit('close'); | ||
} | ||
s.on('close', onClose); | ||
// [patch start] | ||
// start socket timeout handler | ||
function onTimeout() { | ||
debug('CLIENT socket onTimeout'); | ||
s.destroy(); | ||
// Remove it from freeSockets immediately to prevent new requests from being sent through this socket. | ||
self.removeSocket(s, options); | ||
self.emit('timeout'); | ||
} | ||
s.on('timeout', onTimeout); | ||
// set the default timer | ||
s.setTimeout(self.timeout); | ||
// [patch end] | ||
function onTimeout() { | ||
debug('CLIENT socket onTimeout'); | ||
s.destroy(); | ||
// Remove it from freeSockets immediately to prevent new requests from being sent through this socket. | ||
self.removeSocket(s, options); | ||
self.emit('timeout'); | ||
} | ||
s.on('timeout', onTimeout); | ||
// set the default timer | ||
s.setTimeout(self.timeout); | ||
function onRemove() { | ||
// We need this function for cases like HTTP 'upgrade' | ||
// (defined by WebSockets) where we need to remove a socket from the | ||
// pool because it'll be locked up indefinitely | ||
debug('CLIENT socket onRemove'); | ||
self.removeSocket(s, options); | ||
s.removeListener('close', onClose); | ||
s.removeListener('free', onFree); | ||
s.removeListener('agentRemove', onRemove); | ||
function onRemove() { | ||
// We need this function for cases like HTTP 'upgrade' | ||
// (defined by WebSockets) where we need to remove a socket from the | ||
// pool because it'll be locked up indefinitely | ||
debug('CLIENT socket onRemove'); | ||
self.removeSocket(s, options); | ||
s.removeListener('close', onClose); | ||
s.removeListener('free', onFree); | ||
s.removeListener('agentRemove', onRemove); | ||
// remove timer | ||
s.setTimeout(0, onTimeout); | ||
// [patch start] | ||
// remove socket timeout handler | ||
s.setTimeout(0, onTimeout); | ||
// [patch end] | ||
} | ||
s.on('agentRemove', onRemove); | ||
cb(null, s); | ||
} | ||
s.on('agentRemove', onRemove); | ||
return s; | ||
}; | ||
Agent.prototype.removeSocket = function(s, options) { | ||
var freeLen, sockLen; | ||
Agent.prototype.removeSocket = function removeSocket(s, options) { | ||
var name = this.getName(options); | ||
debug('removeSocket', name, 'destroyed:', s.destroyed); | ||
debug('removeSocket', name, 'writable:', s.writable); | ||
var sets = [this.sockets]; | ||
// If the socket was destroyed, remove it from the free buffers too. | ||
if (s.destroyed) | ||
if (!s.writable) | ||
sets.push(this.freeSockets); | ||
@@ -318,2 +353,3 @@ | ||
var sockets = sets[sk]; | ||
if (sockets[name]) { | ||
@@ -330,4 +366,6 @@ var index = sockets[name].indexOf(s); | ||
freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0; | ||
sockLen = freeLen + this.sockets[name] ? this.sockets[name].length : 0; | ||
// [patch start] | ||
var freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0; | ||
var sockLen = freeLen + this.sockets[name] ? this.sockets[name].length : 0; | ||
// [patch end] | ||
@@ -338,7 +376,15 @@ if (this.requests[name] && this.requests[name].length && sockLen < this.maxSockets) { | ||
// If we have pending requests and a socket gets closed make a new one | ||
this.createSocket(req, options).emit('free'); | ||
this.createSocket(req, options, function(err, newSocket) { | ||
if (err) { | ||
process.nextTick(function() { | ||
req.emit('error', err); | ||
}); | ||
return; | ||
} | ||
newSocket.emit('free'); | ||
}); | ||
} | ||
}; | ||
Agent.prototype.destroy = function() { | ||
Agent.prototype.destroy = function destroy() { | ||
var sets = [this.freeSockets, this.sockets]; | ||
@@ -345,0 +391,0 @@ for (var s = 0; s < sets.length; s++) { |
147
lib/agent.js
@@ -7,6 +7,2 @@ /** | ||
* * https://github.com/joyent/node/blob/master/lib/_http_agent.js | ||
* | ||
* Copyright(c) 2012 - 2014 fengmk2 <fengmk2@gmail.com> | ||
* Copyright(c) node-modules | ||
* MIT Licensed | ||
*/ | ||
@@ -16,81 +12,88 @@ | ||
/** | ||
* Module dependencies. | ||
*/ | ||
const OriginalAgent = require('./_http_agent').Agent; | ||
var https = require('https'); | ||
var utils = require('./utils'); | ||
var OriginalAgent = require('./_http_agent').Agent; | ||
var OriginalHttpsAgent = https.Agent; | ||
class Agent extends OriginalAgent { | ||
constructor(options) { | ||
options = options || {}; | ||
options.keepAlive = options.keepAlive !== false; | ||
// default is keep-alive and 15s free socket timeout | ||
if (options.freeSocketKeepAliveTimeout === undefined) { | ||
options.freeSocketKeepAliveTimeout = 15000; | ||
} | ||
// Legacy API: keepAliveTimeout should be rename to `freeSocketKeepAliveTimeout` | ||
if (options.keepAliveTimeout) { | ||
options.freeSocketKeepAliveTimeout = options.keepAliveTimeout; | ||
} | ||
module.exports = Agent; | ||
// Sets the socket to timeout after timeout milliseconds of inactivity on the socket. | ||
// By default is double free socket keepalive timeout. | ||
if (options.timeout === undefined) { | ||
options.timeout = options.freeSocketKeepAliveTimeout * 2; | ||
// make sure socket default inactivity timeout >= 30000 | ||
if (options.timeout < 30000) { | ||
options.timeout = 30000; | ||
} | ||
} | ||
function Agent(options) { | ||
if (!(this instanceof Agent)) { | ||
return new Agent(options); | ||
super(options); | ||
this.createSocketCount = 0; | ||
this.createSocketErrorCount = 0; | ||
this.closeSocketCount = 0; | ||
// socket error event count | ||
this.errorSocketCount = 0; | ||
this.requestCount = 0; | ||
this.timeoutSocketCount = 0; | ||
this.on('free', s => { | ||
this.requestCount++; | ||
// last enter free queue timestamp | ||
s.lastFreeTime = Date.now(); | ||
}); | ||
this.on('timeout', () => { | ||
this.timeoutSocketCount++; | ||
}); | ||
this.on('close', () => { | ||
this.closeSocketCount++; | ||
}); | ||
this.on('error', () => { | ||
this.errorSocketCount++; | ||
}); | ||
} | ||
options = options || {}; | ||
options.keepAlive = options.keepAlive !== false; | ||
// default is keep-alive and 15s free socket timeout | ||
if (options.keepAliveTimeout === undefined) { | ||
options.keepAliveTimeout = 15000; | ||
createSocket(req, options, cb) { | ||
super.createSocket(req, options, (err, socket) => { | ||
if (err) { | ||
this.createSocketErrorCount++; | ||
return cb(err); | ||
} | ||
if (this.keepAlive) { | ||
// Disable Nagle's algorithm: http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/ | ||
// https://fengmk2.com/benchmark/nagle-algorithm-delayed-ack-mock.html | ||
socket.setNoDelay(true); | ||
} | ||
this.createSocketCount++; | ||
cb(null, socket); | ||
}); | ||
} | ||
// default timeout is double keepalive timeout | ||
if (options.timeout === undefined) { | ||
options.timeout = options.keepAliveTimeout * 2; | ||
getCurrentStatus() { | ||
return { | ||
createSocketCount: this.createSocketCount, | ||
createSocketErrorCount: this.createSocketErrorCount, | ||
closeSocketCount: this.closeSocketCount, | ||
errorSocketCount: this.errorSocketCount, | ||
timeoutSocketCount: this.timeoutSocketCount, | ||
requestCount: this.requestCount, | ||
freeSockets: inspect(this.freeSockets), | ||
sockets: inspect(this.sockets), | ||
requests: inspect(this.requests), | ||
}; | ||
} | ||
OriginalAgent.call(this, options); | ||
var self = this; | ||
self.createSocketCount = 0; | ||
self.closeSocketCount = 0; | ||
// socket error event count | ||
self.errorSocketCount = 0; | ||
self.requestCount = 0; | ||
self.timeoutSocketCount = 0; | ||
self.on('free', function () { | ||
self.requestCount++; | ||
}); | ||
self.on('timeout', function () { | ||
self.timeoutSocketCount++; | ||
}); | ||
self.on('close', function () { | ||
self.closeSocketCount++; | ||
}); | ||
self.on('error', function () { | ||
self.errorSocketCount++; | ||
}); | ||
} | ||
utils.inherits(Agent, OriginalAgent); | ||
module.exports = Agent; | ||
Agent.prototype.createSocket = function (req, options) { | ||
var socket = OriginalAgent.prototype.createSocket.call(this, req, options); | ||
if (this.keepAlive) { | ||
// Disable Nagle's algorithm: http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/ | ||
// http://fengmk2.com/benchmark/nagle-algorithm-delayed-ack-mock.html | ||
socket.setNoDelay(true); | ||
} | ||
this.createSocketCount++; | ||
return socket; | ||
}; | ||
Agent.prototype.getCurrentStatus = function () { | ||
return { | ||
createSocketCount: this.createSocketCount, | ||
closeSocketCount: this.closeSocketCount, | ||
errorSocketCount: this.errorSocketCount, | ||
timeoutSocketCount: this.timeoutSocketCount, | ||
requestCount: this.requestCount, | ||
freeSockets: inspect(this.freeSockets), | ||
sockets: inspect(this.sockets), | ||
requests: inspect(this.requests) | ||
}; | ||
}; | ||
function inspect(obj) { | ||
var res = {}; | ||
for (var key in obj) { | ||
const res = {}; | ||
for (const key in obj) { | ||
res[key] = obj[key].length; | ||
@@ -97,0 +100,0 @@ } |
/** | ||
* Https Agent base on custom http agent | ||
* | ||
* Copyright(c) node-modules and other contributors. | ||
* MIT Licensed | ||
* | ||
* Authors: | ||
* fengmk2 <m@fengmk2.com> (http://fengmk2.com) | ||
*/ | ||
@@ -13,84 +7,37 @@ | ||
/** | ||
* Module dependencies. | ||
*/ | ||
const https = require('https'); | ||
const HttpAgent = require('./agent'); | ||
const OriginalHttpsAgent = https.Agent; | ||
var https = require('https'); | ||
var utils = require('./utils'); | ||
var HttpAgent = require('./agent'); | ||
var OriginalHttpsAgent = https.Agent; | ||
class HttpsAgent extends HttpAgent { | ||
constructor(options) { | ||
super(options); | ||
var HttpsAgent; | ||
if (utils.isNode10) { | ||
// node v0.10 | ||
HttpsAgent = function HttpsAgent(options) { | ||
HttpAgent.call(this, options); | ||
this.defaultPort = 443; | ||
this.protocol = 'https:'; | ||
}; | ||
utils.inherits(HttpsAgent, HttpAgent); | ||
HttpsAgent.prototype.createConnection = https.globalAgent.createConnection; | ||
HttpsAgent.prototype.getName = function(options) { | ||
var name = HttpAgent.prototype.getName.call(this, options); | ||
name += ':'; | ||
if (options.ca) | ||
name += options.ca; | ||
name += ':'; | ||
if (options.cert) | ||
name += options.cert; | ||
name += ':'; | ||
if (options.ciphers) | ||
name += options.ciphers; | ||
name += ':'; | ||
if (options.key) | ||
name += options.key; | ||
name += ':'; | ||
if (options.pfx) | ||
name += options.pfx; | ||
name += ':'; | ||
if (options.rejectUnauthorized !== undefined) | ||
name += options.rejectUnauthorized; | ||
return name; | ||
}; | ||
} else { | ||
HttpsAgent = function HttpsAgent(options) { | ||
HttpAgent.call(this, options); | ||
this.defaultPort = 443; | ||
this.protocol = 'https:'; | ||
this.maxCachedSessions = this.options.maxCachedSessions; | ||
if (this.maxCachedSessions === undefined) | ||
if (this.maxCachedSessions === undefined) { | ||
this.maxCachedSessions = 100; | ||
} | ||
this._sessionCache = { | ||
map: {}, | ||
list: [] | ||
list: [], | ||
}; | ||
}; | ||
} | ||
} | ||
utils.inherits(HttpsAgent, HttpAgent); | ||
[ | ||
'createConnection', | ||
'getName', | ||
'_getSession', | ||
'_cacheSession', | ||
// https://github.com/nodejs/node/pull/4982 | ||
'_evictSession', | ||
].forEach(function(method) { | ||
if (typeof OriginalHttpsAgent.prototype[method] === 'function') { | ||
HttpsAgent.prototype[method] = OriginalHttpsAgent.prototype[method]; | ||
} | ||
}); | ||
[ | ||
'createConnection', | ||
'getName', | ||
'_getSession', | ||
'_cacheSession', | ||
// https://github.com/nodejs/node/pull/4982 | ||
'_evictSession', | ||
].forEach(function(method) { | ||
if (typeof OriginalHttpsAgent.prototype[method] === 'function') { | ||
HttpsAgent.prototype[method] = OriginalHttpsAgent.prototype[method]; | ||
} | ||
}); | ||
} | ||
module.exports = HttpsAgent; |
{ | ||
"name": "agentkeepalive", | ||
"version": "2.2.0", | ||
"version": "3.0.0", | ||
"description": "Missing keepalive http.Agent", | ||
@@ -13,7 +13,6 @@ "main": "index.js", | ||
"scripts": { | ||
"test": "mocha -R spec -t 5000 -r should-http test/*.test.js", | ||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- -t 5000 -r should-http test/*.test.js", | ||
"ci": "npm run lint && npm run test-cov", | ||
"lint": "jshint .", | ||
"codecov": "npm i codecov && codecov" | ||
"test": "egg-bin test", | ||
"cov": "egg-bin cov", | ||
"ci": "npm run lint && npm run cov", | ||
"lint": "eslint lib test index.js" | ||
}, | ||
@@ -36,14 +35,16 @@ "repository": { | ||
"devDependencies": { | ||
"istanbul": "*", | ||
"mocha": "*", | ||
"pedding": "1", | ||
"should": "4", | ||
"should-http": "~0.0.2", | ||
"jshint": "^2.9.1" | ||
"egg-bin": "^1.9.1", | ||
"egg-ci": "^1.1.0", | ||
"eslint": "^3.12.2", | ||
"eslint-config-egg": "^3.2.0", | ||
"pedding": "1" | ||
}, | ||
"engines": { | ||
"node": ">= 0.10.0" | ||
"node": ">= 4.0.0" | ||
}, | ||
"author": "fengmk2 <fengmk2@gmail.com> (http://fengmk2.com)", | ||
"ci": { | ||
"version": "4.3.2, 4, 6, 7" | ||
}, | ||
"author": "fengmk2 <fengmk2@gmail.com> (https://fengmk2.com)", | ||
"license": "MIT" | ||
} |
@@ -28,2 +28,9 @@ # agentkeepalive | ||
## What's different from original `http.Agent`? | ||
- `keepAlive=true` by default | ||
- Disable Nagle's algorithm: `socket.setNoDelay(true)` | ||
- Add free socket timeout: avoid long time inactivity socket leak in the free-sockets queue. | ||
- Add active socket timeout: avoid long time inactivity socket leak in the active-sockets queue. | ||
## Install | ||
@@ -40,8 +47,8 @@ | ||
* `keepAlive` {Boolean} Keep sockets around in a pool to be used by | ||
other requests in the future. Default = `true` | ||
other requests in the future. Default = `true`. | ||
* `keepAliveMsecs` {Number} When using HTTP KeepAlive, how often | ||
to send TCP KeepAlive packets over sockets being kept alive. | ||
Default = `1000`. Only relevant if `keepAlive` is set to `true`. | ||
* `keepAliveTimeout`: {Number} Sets the free socket to timeout | ||
after `keepAliveTimeout` milliseconds of inactivity on the free socket. | ||
* `freeSocketKeepAliveTimeout`: {Number} Sets the free socket to timeout | ||
after `freeSocketKeepAliveTimeout` milliseconds of inactivity on the free socket. | ||
Default is `15000`. | ||
@@ -51,3 +58,3 @@ Only relevant if `keepAlive` is set to `true`. | ||
after `timeout` milliseconds of inactivity on the working socket. | ||
Default is `keepAliveTimeout * 2`. | ||
Default is `freeSocketKeepAliveTimeout * 2`. | ||
* `maxSockets` {Number} Maximum number of sockets to allow per | ||
@@ -62,13 +69,13 @@ host. Default = `Infinity`. | ||
```js | ||
var http = require('http'); | ||
var Agent = require('agentkeepalive'); | ||
const http = require('http'); | ||
const Agent = require('agentkeepalive'); | ||
var keepaliveAgent = new Agent({ | ||
const keepaliveAgent = new Agent({ | ||
maxSockets: 100, | ||
maxFreeSockets: 10, | ||
timeout: 60000, | ||
keepAliveTimeout: 30000 // free socket keepalive for 30 seconds | ||
freeSocketKeepAliveTimeout: 30000, // free socket keepalive for 30 seconds | ||
}); | ||
var options = { | ||
const options = { | ||
host: 'cnodejs.org', | ||
@@ -78,6 +85,6 @@ port: 80, | ||
method: 'GET', | ||
agent: keepaliveAgent | ||
agent: keepaliveAgent, | ||
}; | ||
var req = http.request(options, function (res) { | ||
const req = http.request(options, res => { | ||
console.log('STATUS: ' + res.statusCode); | ||
@@ -90,4 +97,3 @@ console.log('HEADERS: ' + JSON.stringify(res.headers)); | ||
}); | ||
req.on('error', function (e) { | ||
req.on('error', e => { | ||
console.log('problem with request: ' + e.message); | ||
@@ -97,5 +103,4 @@ }); | ||
setTimeout(function () { | ||
console.log('keep alive sockets:'); | ||
console.log(keepaliveAgent.unusedSockets); | ||
setTimeout(() => { | ||
console.log('agent status: %j', keepaliveAgent.getCurrentStatus()); | ||
}, 2000); | ||
@@ -115,4 +120,4 @@ | ||
requestCount: 5, | ||
freeSockets: { 'localhost:57479::': 3 }, | ||
sockets: { 'localhost:57479::': 5 }, | ||
freeSockets: { 'localhost:57479:': 3 }, | ||
sockets: { 'localhost:57479:': 5 }, | ||
requests: {} | ||
@@ -125,8 +130,8 @@ } | ||
```js | ||
var https = require('https'); | ||
var HttpsAgent = require('agentkeepalive').HttpsAgent; | ||
const https = require('https'); | ||
const HttpsAgent = require('agentkeepalive').HttpsAgent; | ||
var keepaliveAgent = new HttpsAgent(); | ||
const keepaliveAgent = new HttpsAgent(); | ||
// https://www.google.com/search?q=nodejs&sugexp=chrome,mod=12&sourceid=chrome&ie=UTF-8 | ||
var options = { | ||
const options = { | ||
host: 'www.google.com', | ||
@@ -136,10 +141,10 @@ port: 443, | ||
method: 'GET', | ||
agent: keepaliveAgent | ||
agent: keepaliveAgent, | ||
}; | ||
var req = https.request(options, function (res) { | ||
const req = https.request(options, res => { | ||
console.log('STATUS: ' + res.statusCode); | ||
console.log('HEADERS: ' + JSON.stringify(res.headers)); | ||
res.setEncoding('utf8'); | ||
res.on('data', function (chunk) { | ||
res.on('data', chunk => { | ||
console.log('BODY: ' + chunk); | ||
@@ -149,3 +154,3 @@ }); | ||
req.on('error', function (e) { | ||
req.on('error', e => { | ||
console.log('problem with request: ' + e.message); | ||
@@ -155,6 +160,4 @@ }); | ||
setTimeout(function () { | ||
console.log('keep alive sockets:'); | ||
console.log(keepaliveAgent.unusedSockets); | ||
process.exit(); | ||
setTimeout(() => { | ||
console.log('agent status: %j', keepaliveAgent.getCurrentStatus()); | ||
}, 2000); | ||
@@ -161,0 +164,0 @@ ``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
27260
5
238
0
2
8
459