agent.js 4.2 KB

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