Skip to content

Commit 616cb04

Browse files
Add FunctionCall.getNumRetries.
FunctionCall.getNumRetries returns the number of times the wrapped function was retried. This fixes #10.
1 parent 2b8e9a8 commit 616cb04

6 files changed

Lines changed: 81 additions & 19 deletions

File tree

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
- Replace `FunctionCall.getResults` by `FunctionCall.getLastResult` to avoid
66
storing intermediary results forever as this may lead to memory exhaustion
77
when used in conjunction with an infinite number of backoffs.
8+
- Add `FunctionCall.getNumRetries` which returns the number of times the
9+
wrapped function was retried.
810

911
## 2.3.0
1012

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ Typical usage looks like the following.
9090

9191
``` js
9292
var call = backoff.call(get, 'https://duplika.ca/', function(err, res) {
93+
console.log('Num retries: ' + call.getNumRetries());
94+
9395
if (err) {
9496
console.log('Error: ' + err.message);
9597
} else {
@@ -306,6 +308,13 @@ var results = call.getLastResult();
306308
var error = results[0];
307309
```
308310

311+
#### call.getNumRetries()
312+
313+
Returns the number of times the wrapped function call was retried. For a
314+
wrapped function that succeeded immediately, this would return 0. This
315+
method can be called at any point in time during the call life cycle, i.e.
316+
before, during and after the wrapped function invocation.
317+
309318
#### call.start()
310319

311320
Initiates the call the wrapped function. This method should only be called

docs/function_call.html

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ <h1>function_call.js</h1>
104104
<span class="keyword">this</span>.arguments_ = args;
105105
<span class="keyword">this</span>.callback_ = callback;
106106
<span class="keyword">this</span>.lastResult_ = [];
107+
<span class="keyword">this</span>.numRetries_ = <span class="number">0</span>;
107108

108109
<span class="keyword">this</span>.backoff_ = <span class="literal">null</span>;
109110
<span class="keyword">this</span>.strategy_ = <span class="literal">null</span>;
@@ -305,6 +306,23 @@ <h1>function_call.js</h1>
305306
<div class="pilwrap ">
306307
<a class="pilcrow" href="#section-14">&#182;</a>
307308
</div>
309+
<p>Returns the number of times the wrapped function call was retried.</p>
310+
311+
</div>
312+
313+
<div class="content"><div class='highlight'><pre>FunctionCall.prototype.getNumRetries = <span class="keyword">function</span>() {
314+
<span class="keyword">return</span> <span class="keyword">this</span>.numRetries_;
315+
};</pre></div></div>
316+
317+
</li>
318+
319+
320+
<li id="section-15">
321+
<div class="annotation">
322+
323+
<div class="pilwrap ">
324+
<a class="pilcrow" href="#section-15">&#182;</a>
325+
</div>
308326
<p>Sets the backoff limit.</p>
309327

310328
</div>
@@ -318,11 +336,11 @@ <h1>function_call.js</h1>
318336
</li>
319337

320338

321-
<li id="section-15">
339+
<li id="section-16">
322340
<div class="annotation">
323341

324342
<div class="pilwrap ">
325-
<a class="pilcrow" href="#section-15">&#182;</a>
343+
<a class="pilcrow" href="#section-16">&#182;</a>
326344
</div>
327345
<p>Aborts the call.</p>
328346

@@ -341,11 +359,11 @@ <h1>function_call.js</h1>
341359
</li>
342360

343361

344-
<li id="section-16">
362+
<li id="section-17">
345363
<div class="annotation">
346364

347365
<div class="pilwrap ">
348-
<a class="pilcrow" href="#section-16">&#182;</a>
366+
<a class="pilcrow" href="#section-17">&#182;</a>
349367
</div>
350368
<p>Initiates the call to the wrapped function. Accepts an optional factory
351369
function used to create the backoff instance; used when testing.</p>
@@ -362,7 +380,7 @@ <h1>function_call.js</h1>
362380
backoffFactory(strategy) :
363381
<span class="keyword">new</span> Backoff(strategy);
364382

365-
<span class="keyword">this</span>.backoff_.on(<span class="string">'ready'</span>, <span class="keyword">this</span>.doCall_.bind(<span class="keyword">this</span>));
383+
<span class="keyword">this</span>.backoff_.on(<span class="string">'ready'</span>, <span class="keyword">this</span>.doCall_.bind(<span class="keyword">this</span>, <span class="literal">true</span> <span class="comment">/* isRetry */</span>));
366384
<span class="keyword">this</span>.backoff_.on(<span class="string">'fail'</span>, <span class="keyword">this</span>.doCallback_.bind(<span class="keyword">this</span>));
367385
<span class="keyword">this</span>.backoff_.on(<span class="string">'backoff'</span>, <span class="keyword">this</span>.handleBackoff_.bind(<span class="keyword">this</span>));
368386

@@ -371,23 +389,26 @@ <h1>function_call.js</h1>
371389
}
372390

373391
<span class="keyword">this</span>.state_ = FunctionCall.State_.RUNNING;
374-
<span class="keyword">this</span>.doCall_();
392+
<span class="keyword">this</span>.doCall_(<span class="literal">false</span> <span class="comment">/* isRetry */</span>);
375393
};</pre></div></div>
376394

377395
</li>
378396

379397

380-
<li id="section-17">
398+
<li id="section-18">
381399
<div class="annotation">
382400

383401
<div class="pilwrap ">
384-
<a class="pilcrow" href="#section-17">&#182;</a>
402+
<a class="pilcrow" href="#section-18">&#182;</a>
385403
</div>
386404
<p>Calls the wrapped function.</p>
387405

388406
</div>
389407

390-
<div class="content"><div class='highlight'><pre>FunctionCall.prototype.doCall_ = <span class="keyword">function</span>() {
408+
<div class="content"><div class='highlight'><pre>FunctionCall.prototype.doCall_ = <span class="keyword">function</span>(isRetry) {
409+
<span class="keyword">if</span> (isRetry) {
410+
<span class="keyword">this</span>.numRetries_++;
411+
}
391412
<span class="keyword">var</span> eventArgs = [<span class="string">'call'</span>].concat(<span class="keyword">this</span>.arguments_);
392413
events.EventEmitter.prototype.emit.apply(<span class="keyword">this</span>, eventArgs);
393414
<span class="keyword">var</span> callback = <span class="keyword">this</span>.handleFunctionCallback_.bind(<span class="keyword">this</span>);
@@ -397,11 +418,11 @@ <h1>function_call.js</h1>
397418
</li>
398419

399420

400-
<li id="section-18">
421+
<li id="section-19">
401422
<div class="annotation">
402423

403424
<div class="pilwrap ">
404-
<a class="pilcrow" href="#section-18">&#182;</a>
425+
<a class="pilcrow" href="#section-19">&#182;</a>
405426
</div>
406427
<p>Calls the wrapped function&#39;s callback with the last result returned by the
407428
wrapped function.</p>
@@ -415,11 +436,11 @@ <h1>function_call.js</h1>
415436
</li>
416437

417438

418-
<li id="section-19">
439+
<li id="section-20">
419440
<div class="annotation">
420441

421442
<div class="pilwrap ">
422-
<a class="pilcrow" href="#section-19">&#182;</a>
443+
<a class="pilcrow" href="#section-20">&#182;</a>
423444
</div>
424445
<p>Handles wrapped function&#39;s completion. This method acts as a replacement
425446
for the original callback function.</p>
@@ -446,11 +467,11 @@ <h1>function_call.js</h1>
446467
</li>
447468

448469

449-
<li id="section-20">
470+
<li id="section-21">
450471
<div class="annotation">
451472

452473
<div class="pilwrap ">
453-
<a class="pilcrow" href="#section-20">&#182;</a>
474+
<a class="pilcrow" href="#section-21">&#182;</a>
454475
</div>
455476
<p>Handles the backoff event by reemitting it.</p>
456477

examples/function_call.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function get(options, callback) {
2727

2828
var call = backoff.call(get, URL, function(err, res) {
2929
// Notice how the call is captured inside the closure.
30-
console.log('Last result: ' + util.inspect(call.getLastResult()));
30+
console.log('Num retries: ' + call.getNumRetries());
3131

3232
if (err) {
3333
console.log('Error: ' + err.message);

lib/function_call.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ function FunctionCall(fn, args, callback) {
2020
this.arguments_ = args;
2121
this.callback_ = callback;
2222
this.lastResult_ = [];
23+
this.numRetries_ = 0;
2324

2425
this.backoff_ = null;
2526
this.strategy_ = null;
@@ -76,6 +77,11 @@ FunctionCall.prototype.getLastResult = function() {
7677
return this.lastResult_.concat();
7778
};
7879

80+
// Returns the number of times the wrapped function call was retried.
81+
FunctionCall.prototype.getNumRetries = function() {
82+
return this.numRetries_;
83+
};
84+
7985
// Sets the backoff limit.
8086
FunctionCall.prototype.failAfter = function(maxNumberOfRetry) {
8187
precond.checkState(this.isPending(), 'FunctionCall in progress.');
@@ -106,7 +112,7 @@ FunctionCall.prototype.start = function(backoffFactory) {
106112
backoffFactory(strategy) :
107113
new Backoff(strategy);
108114

109-
this.backoff_.on('ready', this.doCall_.bind(this));
115+
this.backoff_.on('ready', this.doCall_.bind(this, true /* isRetry */));
110116
this.backoff_.on('fail', this.doCallback_.bind(this));
111117
this.backoff_.on('backoff', this.handleBackoff_.bind(this));
112118

@@ -115,11 +121,14 @@ FunctionCall.prototype.start = function(backoffFactory) {
115121
}
116122

117123
this.state_ = FunctionCall.State_.RUNNING;
118-
this.doCall_();
124+
this.doCall_(false /* isRetry */);
119125
};
120126

121127
// Calls the wrapped function.
122-
FunctionCall.prototype.doCall_ = function() {
128+
FunctionCall.prototype.doCall_ = function(isRetry) {
129+
if (isRetry) {
130+
this.numRetries_++;
131+
}
123132
var eventArgs = ['call'].concat(this.arguments_);
124133
events.EventEmitter.prototype.emit.apply(this, eventArgs);
125134
var callback = this.handleFunctionCallback_.bind(this);

tests/function_call.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,27 @@ exports["FunctionCall"] = {
259259
test.done();
260260
},
261261

262+
"getNumRetries should return the number of retries": function(test) {
263+
var call = new FunctionCall(this.wrappedFn, [], this.callback);
264+
265+
this.wrappedFn.yields(1);
266+
call.start(this.backoffFactory);
267+
// The inital call doesn't count as a retry.
268+
test.equals(0, call.getNumRetries());
269+
270+
for (var i = 2; i < 5; i++) {
271+
this.wrappedFn.yields(i);
272+
this.backoff.emit('ready');
273+
test.equals(i - 1, call.getNumRetries());
274+
}
275+
276+
this.wrappedFn.yields(null);
277+
this.backoff.emit('ready');
278+
test.equals(4, call.getNumRetries());
279+
280+
test.done();
281+
},
282+
262283
"wrapped function's errors should be propagated": function(test) {
263284
var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback);
264285
this.wrappedFn.throws(new Error());

0 commit comments

Comments
 (0)