Skip to content
This repository has been archived by the owner on Apr 25, 2019. It is now read-only.

Commit

Permalink
Adds reqInfo object to pool.request callback
Browse files Browse the repository at this point in the history
This change is a little specific, so no pressure to merge. It adds an additional callback argument
to pool.request, namely, requestInfo. It is a dictionary containing information about the node that
responded to the request, nodes that failed to respond to the request, and the number of total
retries.

It does this by creating a closure when preparing to handle the response containing the node that
the response is coming from.
  • Loading branch information
Russell Cohen committed Dec 13, 2013
1 parent cc79dfa commit 7ad69d1
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 6 deletions.
4 changes: 2 additions & 2 deletions lib/pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,11 @@ module.exports = function (inherits, EventEmitter, Endpoint, RequestSet) {
options.stream = (options.stream === undefined) ? callback.length === 2 : options.stream

var started = Date.now()
RequestSet.request(this, options, function (err, res, body) {
RequestSet.request(this, options, function (err, res, body, reqInfo) {
options.success = !err
options.reused = res && res.socket && (res.socket._requestCount || 1) > 1
self.emit('timing', Date.now() - started, options)
callback(err, res, body)
callback(err, res, body, reqInfo)
})
}

Expand Down
22 changes: 19 additions & 3 deletions lib/request_set.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,21 @@ function exponentialBackoff(attempt, delay) {
return Math.random() * Math.pow(2, attempt) * delay
}

function handleResponseFromNode(node) {
return function(err, response, body) {
return handleResponse.bind(this)(err, response, body, node);
}
}

// this = RequestSet
function handleResponse(err, response, body) {
function handleResponse(err, response, body, respondingNode) {
this.attemptsLeft--
if (!this.reqInfo) { this.reqInfo = {} };
if (err) {
if (!this.reqInfo.failedNodes) {
this.reqInfo.failedNodes = [];
}
this.reqInfo.failedNodes.push(respondingNode.name);
var delay = (err.delay === true)
? exponentialBackoff(this.attempts - this.attemptsLeft, this.delay)
: err.delay
Expand All @@ -63,7 +74,12 @@ function handleResponse(err, response, body) {
}
}
if (this.callback) {
this.callback(err, response, body)
this.reqInfo.numRetries = this.attempts - this.attemptsLeft;
if (respondingNode) {
this.reqInfo.respondingNode = respondingNode.name;
}

this.callback(err, response, body, this.reqInfo)
this.callback = null
}
}
Expand All @@ -86,7 +102,7 @@ RequestSet.request = function (pool, options, callback) {

RequestSet.prototype.doRequest = function () {
var node = this.pool.get_node()
node.request(this.options, handleResponse.bind(this))
node.request(this.options, handleResponseFromNode(node).bind(this))
}

module.exports = RequestSet
Expand Down
12 changes: 11 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ pool.request(
, stream: false // stream instead of buffer response body
}
,
function (error, response, body) {}
function (error, response, body, requestInfo) {}
)
```

Expand All @@ -193,6 +193,16 @@ pool.request(
A callback with 2 arguments will stream the response and not buffer the
response body.

The fourth callback argument, `requestInfo` contains information about how the request was handled by
the pool, namely:

```javascript
{ numRetries: 3 // number of times the request was made
, failedNodes: ['www.foo.com:99', 'www.foo2.com:99'] // nodes that failed to handle the request
, respondingNode: 'www.foo3.com:99' // The node that handled the request sucesfully
}
```

```javascript
pool.request('/foo', function (error, response) {
response.pipe(somewhere)
Expand Down
20 changes: 20 additions & 0 deletions test/requestset_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,26 @@ describe("RequestSet", function () {
})
})

it("passes back a requestInfo containing information about the request", function(done) {
var p = {
i: 0,
options: { maxRetries: 5 },
get_node: function () { return this.nodes[this.i++]},
onRetry: function () {},
length: 3,
nodes: [{ name: "fail_node", request: hangup_request }, {name: "fail_node2", request: failing_request}, { name: "succeed_node", request: succeeding_request }]
}
RequestSet.request(p, {}, function (err, res, body, requestInfo) {
assert.equal(err, null)
assert.equal(body, "foo")
assert(requestInfo, "requestInfo should be non-null");
assert.deepEqual(requestInfo.failedNodes, ['fail_node', 'fail_node2']);
assert.deepEqual(requestInfo.respondingNode, 'succeed_node');
assert.equal(requestInfo.numRetries, 3);
done()
})
});

it("retries hangups identically to other requests then fails", function (done) {
var p = {
i: 0,
Expand Down

0 comments on commit 7ad69d1

Please sign in to comment.