Hi Joe.
Definitely not an RTM question. This is an advanced usage, combining newRequest for request redirection, and onResponse for response interception. We don't have an example to follow yet, and there's a lot of objects floating around. The key is to register for the response after you've done the request redirection: you use newRequest to send it to vs_a, and then it'll pop up in vs_a's request handler just like any other request. Once there, register for the response handler.
Here's an example, based on yours but with the MySQL parts removed for clarity:
vsm = require('lrs/virtualServerModule');
var vs, vs_a, vs_b;
vsm.on('exist', 'vs', function (vs) {
vs.on('request', function redirectRequest(servReq, servResp, next) {
// Pseudo-randomly redirect to vs_a or vs_b.
var opt_in = (Date.now() % 2 === 0);
if (!opt_in || (!vs_b && vs_a)) {
vs_a.newRequest(servReq, servResp, next);
} else if (vs_b) {
vs_b.newRequest(servReq, servResp, next);
} else {
servResp.writeHead(502, { 'Content-Type' : 'text/plain' });
servResp.end('neither vs_a nor vs_b configured, forwarding impossible.');
next();
}
});
});
vsm.on('exist', 'vs_a', function (newVs) {
vs_a = newVs;
vs_a.on('request', function onVsARequest(servReq, servResp, next) {
// REGISTER FOR RESPONSE CALLBACK HERE, IN THE TARGET VS
servReq.on('response', function processResponseA(cliResp) {
// PROCESS RESPONSE HERE, IN THE RESPONSE CALLBACK REGISTERED
// ONCE THE REQUEST ARRIVED AT THE TARGET VS
cliResp.bindHeaders(servResp);
servResp.setHeader('X-Forwarded-Through', 'vs_a');
cliResp.pipe(servResp);
});
next();
});
});
vsm.on('exist', 'vs_b', function (newVs) {
vs_b = newVs;
vs_b.on('request', function onVsBRequest(servReq, servResp, next) {
// REGISTER FOR RESPONSE CALLBACK HERE, IN THE TARGET VS
servReq.on('response', function processResponseB(cliResp) {
// PROCESS RESPONSE HERE, IN THE RESPONSE CALLBACK REGISTERED
// ONCE THE REQUEST ARRIVED AT THE TARGET VS
cliResp.bindHeaders(servResp);
servResp.setHeader('X-Forwarded-Through', 'vs_b');
cliResp.pipe(servResp);
});
next();
});
});
For processing, all I did was insert an "X-Forwarded-Through" header to show that the response was processed.
The first stage is request redirection with newRequest in the requestRedirect() function:
- When a server request arrives at vs, randomly choose whether to send it to vs_a or vs_b. You'd obviously replace this with your MySQL logic.
- Redirect the server request to vs_a or vs_b using .newRequest.
- Since we're done with the server request in vs, call next().
In the second stage, response interception with onResponse, the request that we redirected with .newRequest pops up in vs_a's or vs_b's request handler. From the perspective of these request handlers, there's nothing special about the request: it could just as well have come off-the-wire from an external client. Now, you do the response interception in onVsARequest or onVsBRequest:
- Register an onResponse callback (a listener named processResponseA/B for the 'response' event on the server request).
- Call next() to send the request along the pipeline; the normal load balancing logic takes over and sends it to the best backend server for vs_a.
- When the response arrives from the server, the processResponseA/B function is invoked with cliResp as the response from the server.
- The processResponseA/B function binds the headers from cliResp to servResp
- The processResponseA/B function sets an 'X-Forwarded-Through' header (just a dummy header for the sake of example)
- The processResponseA/B function pipes the cliResp to servResp.
Joe, I hope this helps you get your response interception script up and going.
p.s. when working in these more complex scripts, I often expand "req" and "resp" variables so I can keep track of what kind of request/responses they are:
- servReq: A node.js-style HTTP.ServerRequest. It is a request that came in from an external client; we are the "server" of this request though we may pass it along to a real server using next().
- servResp: A node.js-style HTTP.ServerResponse. This is the response that we owe to the client: we have to make sure that we either write to this object ourselves, or pipe to it (as in this example), or forward it along using next() so that a real server can write to it.
- cliReq: (not in this example) A node.js-style HTTP.ClientRequest where we are the client.
- cliResp: A node.js-style HTTP.ClientResponse where we are the client. In this example, the cliResp comes from a backend real server, and we just modify it a bit and pipe it through to the external client.