Arlolra has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/246455

Change subject: Remove _http_agent.js
......................................................................

Remove _http_agent.js

 * Instead, inherit from the node exported Agent to do the connection
   timeout thing.

 * Also, do the same https.globalAgent, which we had omitted.  Wasn't
   really an issue so far since the vast majority of requests are sent
   through the proxy.

Change-Id: I88117adc079c4caf16d98985106dc23b9ae0d0fe
---
D lib/_http_agent.js
M lib/mediawiki.ApiRequest.js
2 files changed, 50 insertions(+), 304 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/services/parsoid 
refs/changes/55/246455/1

diff --git a/lib/_http_agent.js b/lib/_http_agent.js
deleted file mode 100644
index 507ad3e..0000000
--- a/lib/_http_agent.js
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var net = require('net');
-var util = require('util');
-var EventEmitter = require('events').EventEmitter;
-var debug = function(){};
-
-// New Agent code.
-
-// The largest departure from the previous implementation is that
-// an Agent instance holds connections for a variable number of host:ports.
-// Surprisingly, this is still API compatible as far as third parties are
-// concerned. The only code that really notices the difference is the
-// request object.
-
-// Another departure is that all code related to HTTP parsing is in
-// ClientRequest.onSocket(). The Agent is now *strictly*
-// concerned with managing a connection pool.
-
-function Agent(options) {
-  if (!(this instanceof Agent))
-    return new Agent(options);
-
-  EventEmitter.call(this);
-
-  var self = this;
-
-  self.defaultPort = 80;
-  self.protocol = 'http:';
-
-  self.options = util._extend({}, options);
-
-  // don't confuse net and make it think that we're connecting to a pipe
-  self.options.path = null;
-  self.requests = {};
-  self.sockets = {};
-  self.freeSockets = {};
-  self.keepAliveMsecs = self.options.keepAliveMsecs || 1000;
-  self.keepAlive = self.options.keepAlive || false;
-  self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets;
-  self.maxFreeSockets = self.options.maxFreeSockets || 256;
-
-  self.on('free', function(socket, options) {
-    var name = self.getName(options);
-    debug('agent.on(free)', name);
-
-    if (!socket.destroyed &&
-        self.requests[name] && self.requests[name].length) {
-      self.requests[name].shift().onSocket(socket);
-      if (self.requests[name].length === 0) {
-        // don't leak
-        delete self.requests[name];
-      }
-    } else {
-      // If there are no pending requests, then put it in
-      // the freeSockets pool, but only if we're allowed to do so.
-      var req = socket._httpMessage;
-      if (req &&
-          req.shouldKeepAlive &&
-          !socket.destroyed &&
-          self.options.keepAlive) {
-        var freeSockets = self.freeSockets[name];
-        var freeLen = freeSockets ? freeSockets.length : 0;
-        var count = freeLen;
-        if (self.sockets[name])
-          count += self.sockets[name].length;
-
-        if (count >= self.maxSockets || freeLen >= self.maxFreeSockets) {
-          self.removeSocket(socket, options);
-          socket.destroy();
-        } else {
-          freeSockets = freeSockets || [];
-          self.freeSockets[name] = freeSockets;
-          socket.setKeepAlive(true, self.keepAliveMsecs);
-          socket.unref();
-          socket._httpMessage = null;
-          self.removeSocket(socket, options);
-          freeSockets.push(socket);
-        }
-      } else {
-        self.removeSocket(socket, options);
-        socket.destroy();
-      }
-    }
-  });
-}
-
-util.inherits(Agent, EventEmitter);
-exports.Agent = Agent;
-
-Agent.defaultMaxSockets = Infinity;
-
-Agent.prototype.createConnection = net.createConnection;
-
-// Get the key for a given set of request options
-Agent.prototype.getName = function(options) {
-  var name = '';
-
-  if (options.host)
-    name += options.host;
-  else
-    name += 'localhost';
-
-  name += ':';
-  if (options.port)
-    name += options.port;
-  name += ':';
-  if (options.localAddress)
-    name += options.localAddress;
-  name += ':';
-  return name;
-};
-
-Agent.prototype.addRequest = function(req, options) {
-  // Legacy API: addRequest(req, host, port, path)
-  if (typeof options === 'string') {
-    options = {
-      host: options,
-      port: arguments[2],
-      path: arguments[3]
-    };
-  }
-
-  var name = this.getName(options);
-  if (!this.sockets[name]) {
-    this.sockets[name] = [];
-  }
-
-  var freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0;
-  var sockLen = freeLen + this.sockets[name].length;
-
-  if (freeLen) {
-    // we have a free socket, so use that.
-    var socket = this.freeSockets[name].shift();
-    debug('have free socket');
-
-    // don't leak
-    if (!this.freeSockets[name].length)
-      delete this.freeSockets[name];
-
-    socket.ref();
-    req.onSocket(socket);
-    this.sockets[name].push(socket);
-  } else if (sockLen < this.maxSockets) {
-    debug('call onSocket', sockLen, freeLen);
-    // If we are under maxSockets create a new one.
-    req.onSocket(this.createSocket(req, options));
-  } else {
-    debug('wait for socket');
-    // We are over limit so we'll add it to the queue.
-    if (!this.requests[name]) {
-      this.requests[name] = [];
-    }
-    this.requests[name].push(req);
-  }
-};
-
-Agent.prototype.createSocket = function(req, options) {
-  var self = this;
-  options = util._extend({}, options);
-  options = util._extend(options, self.options);
-
-  options.servername = options.host;
-  if (req) {
-    var hostHeader = req.getHeader('host');
-    if (hostHeader) {
-      options.servername = hostHeader.replace(/:.*$/, '');
-    }
-  }
-
-  var name = self.getName(options);
-
-  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);
-
-  function onFree() {
-    self.emit('free', s, options);
-  }
-  s.on('free', onFree);
-
-  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);
-  }
-  s.on('close', onClose);
-
-  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);
-  }
-  s.on('agentRemove', onRemove);
-
-  // Set up a connect timeout if connectTimeout option is set
-  if (options.connectTimeout && !s.connectTimeoutTimer) {
-    // Set up a timer
-    s.connectTimeoutTimer = setTimeout(function () {
-      var e = new Error("ETIMEDOUT")
-      e.code = "ETIMEDOUT"
-      s.end();
-      s.emit("error", e)
-         onClose();
-      //console.error('[AgentConnectTimeout ' + hostHeader + ':' + 
options.port + ']');
-    }, options.connectTimeout);
-    s.once('connect',  function() {
-      if (this.connectTimeoutTimer) {
-        //console.log('canceled timeout');
-        clearTimeout(s.connectTimeoutTimer);
-        this.connectTimeoutTimer = undefined;
-      }
-    });
-  }
-
-  return s;
-};
-
-Agent.prototype.removeSocket = function(s, options) {
-  var name = this.getName(options);
-  debug('removeSocket', name, 'destroyed:', s.destroyed);
-  var sets = [this.sockets];
-
-  // If the socket was destroyed, remove it from the free buffers too.
-  if (s.destroyed)
-    sets.push(this.freeSockets);
-
-  sets.forEach(function(sockets) {
-    if (sockets[name]) {
-      var index = sockets[name].indexOf(s);
-      if (index !== -1) {
-        sockets[name].splice(index, 1);
-        // Don't leak
-        if (sockets[name].length === 0)
-          delete sockets[name];
-      }
-    }
-  });
-  if (this.requests[name] && this.requests[name].length) {
-    debug('removeSocket, have a request, make a socket');
-    var req = this.requests[name][0];
-    // If we have pending requests and a socket gets closed make a new one
-    this.createSocket(req, options).emit('free');
-  }
-};
-
-Agent.prototype.destroy = function() {
-  var sets = [this.freeSockets, this.sockets];
-  sets.forEach(function(set) {
-    Object.keys(set).forEach(function(name) {
-      set[name].forEach(function(socket) {
-        socket.destroy();
-      });
-    });
-  });
-};
-
-exports = {
-  Agent: Agent
-};
diff --git a/lib/mediawiki.ApiRequest.js b/lib/mediawiki.ApiRequest.js
index ef183ea..2c84fbc 100644
--- a/lib/mediawiki.ApiRequest.js
+++ b/lib/mediawiki.ApiRequest.js
@@ -1,23 +1,60 @@
 'use strict';
 require('./core-upgrade.js');
 
-// Max concurrency level for accessing the Mediawiki API
-var HTTP_MAX_SOCKETS = 15;
-// Timeout setting for the http agent
-var HTTP_CONNECT_TIMEOUT = 5 * 1000; // 5 seconds
-
-// many concurrent connections to the same host
-var Agent = require('./_http_agent.js').Agent;
-var httpAgent = new Agent({
-       connectTimeout: HTTP_CONNECT_TIMEOUT,
-       maxSockets: HTTP_MAX_SOCKETS,
-});
-require('http').globalAgent = httpAgent;
-
 var request = require('request');
 var events = require('events');
 var util = require('util');
 var domino = require('domino');
+var coreutil = require('util');
+
+
+// Max concurrency level for accessing the Mediawiki API
+var HTTP_MAX_SOCKETS = 15;
+
+// Timeout setting for the http agent
+var HTTP_CONNECT_TIMEOUT = 5 * 1000; // 5 seconds
+
+
+function setupConnectionTimeout(protocol) {
+       var http = require(protocol);
+       var Agent = http.Agent;
+
+       // Many concurrent connections to the same host
+       function ConnectTimeoutAgent() {
+               Agent.apply(this, arguments);
+       }
+       coreutil.inherits(ConnectTimeoutAgent, Agent);
+
+       ConnectTimeoutAgent.prototype.createSocket = function() {
+               var s = Agent.prototype.createSocket.apply(this, arguments);
+               // Set up a connect timeout if connectTimeout option is set
+               if (this.options.connectTimeout && !s.connectTimeoutTimer) {
+                       // Set up a timer
+                       s.connectTimeoutTimer = setTimeout(function () {
+                               var e = new Error('ETIMEDOUT');
+                               e.code = 'ETIMEDOUT';
+                               s.end();
+                               s.emit('error', e);
+                               s.emit('close');
+                       }, this.options.connectTimeout);
+                       s.once('connect',  function() {
+                               if (this.connectTimeoutTimer) {
+                                       clearTimeout(this.connectTimeoutTimer);
+                                       this.connectTimeoutTimer = undefined;
+                               }
+                       });
+               }
+               return s;
+       };
+
+       http.globalAgent = new ConnectTimeoutAgent({
+               connectTimeout: HTTP_CONNECT_TIMEOUT,
+               maxSockets: HTTP_MAX_SOCKETS,
+       });
+}
+setupConnectionTimeout('http');
+setupConnectionTimeout('https');
+
 
 var latestSerial = 0;
 

-- 
To view, visit https://gerrit.wikimedia.org/r/246455
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I88117adc079c4caf16d98985106dc23b9ae0d0fe
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/services/parsoid
Gerrit-Branch: master
Gerrit-Owner: Arlolra <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to