Created
November 9, 2010 18:27
-
-
Save jbalogh/669539 to your computer and use it in GitHub Desktop.
node.js duplex proxy for load testing with production traffic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* A node.js proxy that forwards requests to two upstream servers, but only | |
* returns the response from one. Might be useful for load testing with | |
* production traffic. | |
*/ | |
var http = require('http'); | |
/* The request is forwarded to both proxies, but only the response from proxy1 | |
* is returned. | |
*/ | |
var proxy1 = [8001, 'localhost'], | |
proxy2 = [8002, 'localhost']; | |
var server = function(request, response) { | |
var p1 = http.createClient(proxy1[0], proxy1[1]), | |
p2 = http.createClient(proxy2[0], proxy2[1]), | |
r1 = p1.request(request.method, request.url, request.headers), | |
r2 = p2.request(request.method, request.url, request.headers), | |
start = new(Date), p1Time, p2Time; | |
/* Write request data to both proxies. */ | |
request.on('data', function(chunk) { | |
r1.write(chunk, 'binary'); | |
r2.write(chunk, 'binary'); | |
}); | |
/* Send the primary response back to the client. */ | |
r1.on('response', function(proxy_response) { | |
response.writeHead(proxy_response.statusCode, proxy_response.headers); | |
proxy_response.on('data', function(chunk) { | |
response.write(chunk, 'binary'); | |
}); | |
proxy_response.on('end', function() { | |
response.end(); | |
p1Time = new(Date) - start; | |
status(); | |
}); | |
}); | |
/* Only track the timing for the duplicate request. */ | |
r2.on('response', function(proxy_response) { | |
proxy_response.on('end', function() { | |
p2Time = new(Date) - start; | |
status(); | |
}); | |
}); | |
/* Log response times once both requests are complete. */ | |
var status = function() { | |
if (p1Time && p2Time) { | |
console.log(request.method + ' "' + request.url + '" ' + | |
'p1: ' + p1Time / 1000 + '; p2: ' + p2Time / 1000); | |
} | |
} | |
/* 500 response if something goes wrong with the proxy1. */ | |
var error = function(err) { | |
response.writeHead(500, {'content-type': 'text/plain'}); | |
if (request.method !== 'HEAD') { | |
response.write('Internal Server Error'); | |
} | |
response.end(); | |
}; | |
/* Log issues with the proxy2. */ | |
var busted = function(err) { | |
console.log('Error in proxy 2:\n' + JSON.stringify(err)); | |
}; | |
/* Oh joy, error handling. */ | |
p1.on('error', error), p2.on('error', busted); | |
r1.on('error', error), r2.on('error', busted); | |
r1.end(), r2.end(); | |
}; | |
http.createServer(server).listen(8000); | |
console.log('running on :8000'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment