Permalink
Browse files

initial implementation

  • Loading branch information...
1 parent 09c6974 commit 508a96cd45a6820e7e699706839a897c9d831ed6 @tim-kos committed May 12, 2011
Showing with 138 additions and 3 deletions.
  1. +21 −0 example/dns.js
  2. +1 −0 index.js
  3. +40 −0 lib/retry.js
  4. +70 −0 lib/retry_operation.js
  5. +6 −3 package.json
View
@@ -0,0 +1,21 @@
+var dns = require('dns');
+var retry = require('../lib/retry');
+
+function faultTolerantResolve(address, cb) {
+ var operation = retry.operation();
+
+ operation.try(function() {
+ dns.resolve(address, function(err, addresses) {
+ var result = operation.retry(err);
+ if (!result) {
+ return;
+ }
+
+ cb(operation.mainError(), operation.errors(), addresses);
+ });
+ });
+}
+
+faultTolerantResolve('nodejs.org', function(err, errors, addresses) {
+ console.log(err, errors, addresses);
+});
View
@@ -0,0 +1 @@
+module.exports = require('./lib/retry');
View
@@ -0,0 +1,40 @@
+var RetryOperation = require('./retry_operation');
+exports.operation = function(options) {
+ var timeouts = this.timeouts(options);
+console.warn('timeouts:');
+console.warn(timeouts);
+ var operation = new RetryOperation(timeouts);
+ return operation;
+};
+
+exports.timeouts = function(options) {
+ var opts = {
+ times: 3,
+ factor: 3,
+ minTimeout: 1 * 1000,
+ maxTimeout: 10 * 1000,
+ randomize: false
+ };
+ for (var key in options) {
+ opts[key] = options[key];
+ }
+
+ function createTimeout(num) {
+ var random = opts.randomize ? Math.floor(Math.random() * 2 + 1) : 1;
+ var result = 0;
+ if (num !== 0) {
+ result = Math.min(
+ random * opts.minTimeout * Math.pow(opts.factor, num - 1),
+ opts.maxTimeout
+ );
+ }
+ return result;
+ }
+
+ var timeouts = [];
+ for (var i = 0; i < opts.times; i++) {
+ var timeout = createTimeout(i);
+ timeouts.push(timeout);
+ }
+ return timeouts;
+};
@@ -0,0 +1,70 @@
+function RetryOperation(timeouts) {
+ this.timeouts = timeouts;
+ this.fn = null;
+ this.err = [];
+}
+module.exports = RetryOperation;
+
+RetryOperation.prototype.retry = function(err) {
+ if (!err) {
+ return true;
+ }
+
+ this.err.push(err);
+
+ var self = this;
+ var timeout = this.timeouts.shift();
+
+ if (timeout === undefined) {
+ clearTimeout(this.lastTimeout);
+ return true;
+ }
+
+ setTimeout(function() {
+ self.fn();
+ }, timeout);
+
+ return false;
+};
+
+RetryOperation.prototype.try = function(fn) {
+ this.fn = fn;
+ this.timeouts.shift();
+ this.fn();
+};
+
+RetryOperation.prototype.errors = function(fn) {
+ return this.err;
+};
+
+RetryOperation.prototype.mainError = function() {
+ if (this.err.length === 0) {
+ return null;
+ }
+
+ var errorMap = {};
+
+ // count occurrences of errors
+ for (var i = 0; i < this.err.length; i++) {
+ var msg = this.err[i].message;
+ var error = {msg: msg};
+
+ if (!(msg in errorMap)) {
+ error.occurrences = 1;
+ } else {
+ error.occurrences = errorMap[msg].occurrences + 1;
+ }
+ errorMap[msg] = error;
+ }
+
+ // return the one with most occurrences
+ var mostOccurrences = 0;
+ var result = {};
+ for (var msg in errorMap) {
+ if (errorMap[msg].occurrences > mostOccurrences) {
+ mostOccurrences = errorMap[msg].occurrences;
+ result = errorMap[msg];
+ }
+ }
+ return result;
+};
View
@@ -1,5 +1,5 @@
{
- "author": "Felix Geisendörfer <felix@debuggable.com> (http://debuggable.com/)",
+ "author": "Tim Koschützki <tim@debuggable.com> (http://debuggable.com/)",
"name": "retry",
"description": "Abstraction for exponential and custom retry strategies for failed operations.",
"version": "0.0.1",
@@ -8,10 +8,13 @@
"type": "git",
"url": "git://github.com/felixge/node-retry.git"
},
- "main": "./lib/retry",
+ "directories": {
+ "lib": "./lib"
+ },
+ "main": "index",
"engines": {
"node": "*"
},
"dependencies": {},
"devDependencies": {}
-}
+}

0 comments on commit 508a96c

Please sign in to comment.