1/** 2 * refer: 3 * * @atimb "Real keep-alive HTTP agent": https://gist.github.com/2963672 4 * * https://github.com/joyent/node/blob/master/lib/http.js 5 * * https://github.com/joyent/node/blob/master/lib/https.js 6 * * https://github.com/joyent/node/blob/master/lib/_http_agent.js 7 */ 8 9'use strict'; 10 11const OriginalAgent = require('./_http_agent').Agent; 12const ms = require('humanize-ms'); 13 14class Agent extends OriginalAgent { 15 constructor(options) { 16 options = options || {}; 17 options.keepAlive = options.keepAlive !== false; 18 // default is keep-alive and 15s free socket timeout 19 if (options.freeSocketKeepAliveTimeout === undefined) { 20 options.freeSocketKeepAliveTimeout = 15000; 21 } 22 // Legacy API: keepAliveTimeout should be rename to `freeSocketKeepAliveTimeout` 23 if (options.keepAliveTimeout) { 24 options.freeSocketKeepAliveTimeout = options.keepAliveTimeout; 25 } 26 options.freeSocketKeepAliveTimeout = ms(options.freeSocketKeepAliveTimeout); 27 28 // Sets the socket to timeout after timeout milliseconds of inactivity on the socket. 29 // By default is double free socket keepalive timeout. 30 if (options.timeout === undefined) { 31 options.timeout = options.freeSocketKeepAliveTimeout * 2; 32 // make sure socket default inactivity timeout >= 30s 33 if (options.timeout < 30000) { 34 options.timeout = 30000; 35 } 36 } 37 options.timeout = ms(options.timeout); 38 39 super(options); 40 41 this.createSocketCount = 0; 42 this.createSocketCountLastCheck = 0; 43 44 this.createSocketErrorCount = 0; 45 this.createSocketErrorCountLastCheck = 0; 46 47 this.closeSocketCount = 0; 48 this.closeSocketCountLastCheck = 0; 49 50 // socket error event count 51 this.errorSocketCount = 0; 52 this.errorSocketCountLastCheck = 0; 53 54 this.requestCount = 0; 55 this.requestCountLastCheck = 0; 56 57 this.timeoutSocketCount = 0; 58 this.timeoutSocketCountLastCheck = 0; 59 60 this.on('free', s => { 61 this.requestCount++; 62 // last enter free queue timestamp 63 s.lastFreeTime = Date.now(); 64 }); 65 this.on('timeout', () => { 66 this.timeoutSocketCount++; 67 }); 68 this.on('close', () => { 69 this.closeSocketCount++; 70 }); 71 this.on('error', () => { 72 this.errorSocketCount++; 73 }); 74 } 75 76 createSocket(req, options, cb) { 77 super.createSocket(req, options, (err, socket) => { 78 if (err) { 79 this.createSocketErrorCount++; 80 return cb(err); 81 } 82 if (this.keepAlive) { 83 // Disable Nagle's algorithm: http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/ 84 // https://fengmk2.com/benchmark/nagle-algorithm-delayed-ack-mock.html 85 socket.setNoDelay(true); 86 } 87 this.createSocketCount++; 88 cb(null, socket); 89 }); 90 } 91 92 get statusChanged() { 93 const changed = this.createSocketCount !== this.createSocketCountLastCheck || 94 this.createSocketErrorCount !== this.createSocketErrorCountLastCheck || 95 this.closeSocketCount !== this.closeSocketCountLastCheck || 96 this.errorSocketCount !== this.errorSocketCountLastCheck || 97 this.timeoutSocketCount !== this.timeoutSocketCountLastCheck || 98 this.requestCount !== this.requestCountLastCheck; 99 if (changed) { 100 this.createSocketCountLastCheck = this.createSocketCount; 101 this.createSocketErrorCountLastCheck = this.createSocketErrorCount; 102 this.closeSocketCountLastCheck = this.closeSocketCount; 103 this.errorSocketCountLastCheck = this.errorSocketCount; 104 this.timeoutSocketCountLastCheck = this.timeoutSocketCount; 105 this.requestCountLastCheck = this.requestCount; 106 } 107 return changed; 108 } 109 110 getCurrentStatus() { 111 return { 112 createSocketCount: this.createSocketCount, 113 createSocketErrorCount: this.createSocketErrorCount, 114 closeSocketCount: this.closeSocketCount, 115 errorSocketCount: this.errorSocketCount, 116 timeoutSocketCount: this.timeoutSocketCount, 117 requestCount: this.requestCount, 118 freeSockets: inspect(this.freeSockets), 119 sockets: inspect(this.sockets), 120 requests: inspect(this.requests), 121 }; 122 } 123} 124 125module.exports = Agent; 126 127function inspect(obj) { 128 const res = {}; 129 for (const key in obj) { 130 res[key] = obj[key].length; 131 } 132 return res; 133} 134