diff options
author | Rebecca Turner <me@re-becca.org> | 2015-09-10 00:58:52 +0300 |
---|---|---|
committer | Rebecca Turner <me@re-becca.org> | 2015-09-10 23:47:22 +0300 |
commit | 349c4df356c81aa3db6683f7ad937af641693d14 (patch) | |
tree | bca1da697e3b2ee50047644c351fa3344157d99b /node_modules/npm-registry-client | |
parent | f5075513864fd50ee3f521f8306235c0dd8c2492 (diff) |
retry@0.7.0
Diffstat (limited to 'node_modules/npm-registry-client')
14 files changed, 624 insertions, 0 deletions
diff --git a/node_modules/npm-registry-client/node_modules/retry/.npmignore b/node_modules/npm-registry-client/node_modules/retry/.npmignore new file mode 100644 index 000000000..5a23aa6a0 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/.npmignore @@ -0,0 +1 @@ +/node_modules/* diff --git a/node_modules/npm-registry-client/node_modules/retry/License b/node_modules/npm-registry-client/node_modules/retry/License new file mode 100644 index 000000000..0b58de379 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/License @@ -0,0 +1,21 @@ +Copyright (c) 2011: +Tim Koschützki (tim@debuggable.com) +Felix Geisendörfer (felix@debuggable.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/node_modules/npm-registry-client/node_modules/retry/Makefile b/node_modules/npm-registry-client/node_modules/retry/Makefile new file mode 100644 index 000000000..72baaac19 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/Makefile @@ -0,0 +1,6 @@ +SHELL := /bin/bash + +test: + @node test/runner.js + +.PHONY: test diff --git a/node_modules/npm-registry-client/node_modules/retry/README.md b/node_modules/npm-registry-client/node_modules/retry/README.md new file mode 100644 index 000000000..ba6602205 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/README.md @@ -0,0 +1,167 @@ +# retry + +Abstraction for exponential and custom retry strategies for failed operations. + +## Installation + + npm install retry + +## Current Status + +This module has been tested and is ready to be used. + +## Tutorial + +The example below will retry a potentially failing `dns.resolve` operation +`10` times using an exponential backoff strategy. With the default settings, this +means the last attempt is made after `17 minutes and 3 seconds`. + +``` javascript +var dns = require('dns'); +var retry = require('retry'); + +function faultTolerantResolve(address, cb) { + var operation = retry.operation(); + + operation.attempt(function(currentAttempt) { + dns.resolve(address, function(err, addresses) { + if (operation.retry(err)) { + return; + } + + cb(err ? operation.mainError() : null, addresses); + }); + }); +} + +faultTolerantResolve('nodejs.org', function(err, addresses) { + console.log(err, addresses); +}); +``` + +Of course you can also configure the factors that go into the exponential +backoff. See the API documentation below for all available settings. +currentAttempt is an int representing the number of attempts so far. + +``` javascript +var operation = retry.operation({ + retries: 5, + factor: 3, + minTimeout: 1 * 1000, + maxTimeout: 60 * 1000, + randomize: true, +}); +``` + +## API + +### retry.operation([options]) + +Creates a new `RetryOperation` object. See the `retry.timeouts()` function +below for available `options`. + +### retry.timeouts([options]) + +Returns an array of timeouts. All time `options` and return values are in +milliseconds. If `options` is an array, a copy of that array is returned. + +`options` is a JS object that can contain any of the following keys: + +* `retries`: The maximum amount of times to retry the operation. Default is `10`. +* `factor`: The exponential factor to use. Default is `2`. +* `minTimeout`: The number of milliseconds before starting the first retry. Default is `1000`. +* `maxTimeout`: The maximum number of milliseconds between two retries. Default is `Infinity`. +* `randomize`: Randomizes the timeouts by multiplying with a factor between `1` to `2`. Default is `false`. + +The formula used to calculate the individual timeouts is: + +``` +var Math.min(random * minTimeout * Math.pow(factor, attempt), maxTimeout); +``` + +Have a look at [this article][article] for a better explanation of approach. + +If you want to tune your `factor` / `times` settings to attempt the last retry +after a certain amount of time, you can use wolfram alpha. For example in order +to tune for `10` attempts in `5 minutes`, you can use this equation: + +![screenshot](https://github.com/tim-kos/node-retry/raw/master/equation.gif) + +Explaining the various values from left to right: + +* `k = 0 ... 9`: The `retries` value (10) +* `1000`: The `minTimeout` value in ms (1000) +* `x^k`: No need to change this, `x` will be your resulting factor +* `5 * 60 * 1000`: The desired total amount of time for retrying in ms (5 minutes) + +To make this a little easier for you, use wolfram alpha to do the calculations: + +[http://www.wolframalpha.com/input/?i=Sum%5B1000*x^k%2C+{k%2C+0%2C+9}%5D+%3D+5+*+60+*+1000]() + +[article]: http://dthain.blogspot.com/2009/02/exponential-backoff-in-distributed.html + +### new RetryOperation(timeouts) + +Creates a new `RetryOperation` where `timeouts` is an array where each value is +a timeout given in milliseconds. + +#### retryOperation.errors() + +Returns an array of all errors that have been passed to +`retryOperation.retry()` so far. + +#### retryOperation.mainError() + +A reference to the error object that occured most frequently. Errors are +compared using the `error.message` property. + +If multiple error messages occured the same amount of time, the last error +object with that message is returned. + +If no errors occured so far, the value is `null`. + +#### retryOperation.attempt(fn, timeoutOps) + +Defines the function `fn` that is to be retried and executes it for the first +time right away. The `fn` function can receive an optional `currentAttempt` callback that represents the number of attempts to execute `fn` so far. + +Optionally defines `timeoutOps` which is an object having a property `timeout` in miliseconds and a property `cb` callback function. +Whenever your retry operation takes longer than `timeout` to execute, the timeout callback function `cb` is called. + + +#### retryOperation.try(fn) + +This is an alias for `retryOperation.attempt(fn)`. This is deprecated. + +#### retryOperation.start(fn) + +This is an alias for `retryOperation.attempt(fn)`. This is deprecated. + +#### retryOperation.retry(error) + +Returns `false` when no `error` value is given, or the maximum amount of retries +has been reached. + +Otherwise it returns `true`, and retries the operation after the timeout for +the current attempt number. + +#### retryOperation.attempts() + +Returns an int representing the number of attempts it took to call `fn` before it was successful. + +## License + +retry is licensed under the MIT license. + + +#Changelog + +0.6.0 Introduced optional timeOps parameter for the attempt() function which is an object having a property timeout in miliseconds and a property cb callback function. Whenever your retry operation takes longer than timeout to execute, the timeout callback function cb is called. + +0.5.0 Some minor refactorings. + +0.4.0 Changed retryOperation.try() to retryOperation.attempt(). Deprecated the aliases start() and try() for it. + +0.3.0 Added retryOperation.start() which is an alias for retryOperation.try(). + +0.2.0 Added attempts() function and parameter to retryOperation.try() representing the number of attempts it took to call fn(). diff --git a/node_modules/npm-registry-client/node_modules/retry/equation.gif b/node_modules/npm-registry-client/node_modules/retry/equation.gif Binary files differnew file mode 100644 index 000000000..97107237b --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/equation.gif diff --git a/node_modules/npm-registry-client/node_modules/retry/example/dns.js b/node_modules/npm-registry-client/node_modules/retry/example/dns.js new file mode 100644 index 000000000..e4082af72 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/example/dns.js @@ -0,0 +1,31 @@ +var dns = require('dns'); +var retry = require('../lib/retry'); + +function faultTolerantResolve(address, cb) { + var opts = { + times: 2, + factor: 2, + minTimeout: 1 * 1000, + maxTimeout: 2 * 1000, + randomize: true + }; + var operation = retry.operation(opts); + + operation.attempt(function(currentAttempt) { + dns.resolve(address, function(err, addresses) { + if (operation.retry(err)) { + return; + } + + cb(operation.mainError(), operation.errors(), addresses); + }); + }); +} + +faultTolerantResolve('nodejs.org', function(err, errors, addresses) { + console.warn('err:'); + console.log(err); + + console.warn('addresses:'); + console.log(addresses); +});
\ No newline at end of file diff --git a/node_modules/npm-registry-client/node_modules/retry/index.js b/node_modules/npm-registry-client/node_modules/retry/index.js new file mode 100644 index 000000000..ee62f3a11 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/retry');
\ No newline at end of file diff --git a/node_modules/npm-registry-client/node_modules/retry/lib/retry.js b/node_modules/npm-registry-client/node_modules/retry/lib/retry.js new file mode 100644 index 000000000..38406860d --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/lib/retry.js @@ -0,0 +1,50 @@ +var RetryOperation = require('./retry_operation'); + +exports.operation = function(options) { + var timeouts = exports.timeouts(options); + return new RetryOperation(timeouts); +}; + +exports.timeouts = function(options) { + if (options instanceof Array) { + return [].concat(options); + } + + var opts = { + retries: 10, + factor: 2, + minTimeout: 1 * 1000, + maxTimeout: Infinity, + randomize: false + }; + for (var key in options) { + opts[key] = options[key]; + } + + if (opts.minTimeout > opts.maxTimeout) { + throw new Error('minTimeout is greater than maxTimeout'); + } + + var timeouts = []; + for (var i = 0; i < opts.retries; i++) { + timeouts.push(this._createTimeout(i, opts)); + } + + // sort the array numerically ascending + timeouts.sort(function(a,b) { + return a - b; + }); + + return timeouts; +}; + +exports._createTimeout = function(attempt, opts) { + var random = (opts.randomize) + ? (Math.random() + 1) + : 1; + + var timeout = Math.round(random * opts.minTimeout * Math.pow(opts.factor, attempt)); + timeout = Math.min(timeout, opts.maxTimeout); + + return timeout; +};
\ No newline at end of file diff --git a/node_modules/npm-registry-client/node_modules/retry/lib/retry_operation.js b/node_modules/npm-registry-client/node_modules/retry/lib/retry_operation.js new file mode 100644 index 000000000..f24d2d5a4 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/lib/retry_operation.js @@ -0,0 +1,109 @@ +function RetryOperation(timeouts) { + this._timeouts = timeouts; + this._fn = null; + this._errors = []; + this._attempts = 1; + this._operationTimeout = null; + this._operationTimeoutCb = null; + this._timeout = null; +} +module.exports = RetryOperation; + +RetryOperation.prototype.retry = function(err) { + if (this._timeout) { + clearTimeout(this._timeout); + } + + if (!err) { + return false; + } + + this._errors.push(err); + + var timeout = this._timeouts.shift(); + if (timeout === undefined) { + return false; + } + + this._attempts++; + + var self = this; + setTimeout(function() { + self._fn(self._attempts); + + if (self._operationTimeoutCb) { + self._timeout = setTimeout(function() { + self._operationTimeoutCb(self._attempts); + }, self._operationTimeout); + } + }, timeout); + + return true; +}; + +RetryOperation.prototype.attempt = function(fn, timeoutOps) { + this._fn = fn; + + if (timeoutOps) { + if (timeoutOps.timeout) { + this._operationTimeout = timeoutOps.timeout; + } + if (timeoutOps.cb) { + this._operationTimeoutCb = timeoutOps.cb; + } + } + + this._fn(this._attempts); + + var self = this; + if (this._operationTimeoutCb) { + this._timeout = setTimeout(function() { + self._operationTimeoutCb(); + }, self._operationTimeout); + } +}; + +RetryOperation.prototype.try = function(fn) { + console.log('Using RetryOperation.try() is deprecated'); + this.attempt(fn); +}; + +RetryOperation.prototype.start = function(fn) { + console.log('Using RetryOperation.start() is deprecated'); + this.attempt(fn); +}; + +RetryOperation.prototype.start = RetryOperation.prototype.try; + +RetryOperation.prototype.errors = function() { + return this._errors; +}; + +RetryOperation.prototype.attempts = function() { + return this._attempts; +}; + +RetryOperation.prototype.mainError = function() { + if (this._errors.length === 0) { + return null; + } + + var counts = {}; + var mainError = null; + var mainErrorCount = 0; + + for (var i = 0; i < this._errors.length; i++) { + var error = this._errors[i]; + var message = error.message; + var count = (counts[message] || 0) + 1; + + counts[message] = count; + + if (count >= mainErrorCount) { + mainError = error; + mainErrorCount = count; + } + } + + return mainError; +};
\ No newline at end of file diff --git a/node_modules/npm-registry-client/node_modules/retry/package.json b/node_modules/npm-registry-client/node_modules/retry/package.json new file mode 100644 index 000000000..95d7a67a6 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/package.json @@ -0,0 +1,74 @@ +{ + "_args": [ + [ + "retry@^0.6.1", + "/Users/rebecca/code/npm/node_modules/npm-registry-client" + ] + ], + "_from": "retry@>=0.6.1 <0.7.0", + "_id": "retry@0.6.1", + "_inCache": true, + "_location": "/npm-registry-client/retry", + "_npmUser": { + "email": "tim@debuggable.com", + "name": "tim-kos" + }, + "_npmVersion": "1.4.9", + "_phantomChildren": {}, + "_requested": { + "name": "retry", + "raw": "retry@^0.6.1", + "rawSpec": "^0.6.1", + "scope": null, + "spec": ">=0.6.1 <0.7.0", + "type": "range" + }, + "_requiredBy": [ + "/npm-registry-client" + ], + "_resolved": "https://registry.npmjs.org/retry/-/retry-0.6.1.tgz", + "_shasum": "fdc90eed943fde11b893554b8cc63d0e899ba918", + "_shrinkwrap": null, + "_spec": "retry@^0.6.1", + "_where": "/Users/rebecca/code/npm/node_modules/npm-registry-client", + "author": { + "email": "tim@debuggable.com", + "name": "Tim Koschützki", + "url": "http://debuggable.com/" + }, + "bugs": { + "url": "https://github.com/tim-kos/node-retry/issues" + }, + "dependencies": {}, + "description": "Abstraction for exponential and custom retry strategies for failed operations.", + "devDependencies": { + "fake": "0.2.0", + "far": "0.0.1" + }, + "directories": { + "lib": "./lib" + }, + "dist": { + "shasum": "fdc90eed943fde11b893554b8cc63d0e899ba918", + "tarball": "http://registry.npmjs.org/retry/-/retry-0.6.1.tgz" + }, + "engines": { + "node": "*" + }, + "homepage": "https://github.com/tim-kos/node-retry", + "installable": true, + "main": "index", + "maintainers": [ + { + "name": "tim-kos", + "email": "tim@debuggable.com" + } + ], + "name": "retry", + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git://github.com/tim-kos/node-retry.git" + }, + "version": "0.6.1" +} diff --git a/node_modules/npm-registry-client/node_modules/retry/test/common.js b/node_modules/npm-registry-client/node_modules/retry/test/common.js new file mode 100644 index 000000000..224720696 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/test/common.js @@ -0,0 +1,10 @@ +var common = module.exports; +var path = require('path'); + +var rootDir = path.join(__dirname, '..'); +common.dir = { + lib: rootDir + '/lib' +}; + +common.assert = require('assert'); +common.fake = require('fake');
\ No newline at end of file diff --git a/node_modules/npm-registry-client/node_modules/retry/test/integration/test-retry-operation.js b/node_modules/npm-registry-client/node_modules/retry/test/integration/test-retry-operation.js new file mode 100644 index 000000000..d873d1fa8 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/test/integration/test-retry-operation.js @@ -0,0 +1,80 @@ +var common = require('../common'); +var assert = common.assert; +var fake = common.fake.create(); +var retry = require(common.dir.lib + '/retry'); + +(function testErrors() { + var operation = retry.operation(); + + var error = new Error('some error'); + var error2 = new Error('some other error'); + operation._errors.push(error); + operation._errors.push(error2); + + assert.deepEqual(operation.errors(), [error, error2]); +})(); + +(function testMainErrorReturnsMostFrequentError() { + var operation = retry.operation(); + var error = new Error('some error'); + var error2 = new Error('some other error'); + + operation._errors.push(error); + operation._errors.push(error2); + operation._errors.push(error); + + assert.strictEqual(operation.mainError(), error); +})(); + +(function testMainErrorReturnsLastErrorOnEqualCount() { + var operation = retry.operation(); + var error = new Error('some error'); + var error2 = new Error('some other error'); + + operation._errors.push(error); + operation._errors.push(error2); + + assert.strictEqual(operation.mainError(), error2); +})(); + +(function testAttempt() { + var operation = retry.operation(); + var fn = new Function(); + + var timeoutOpts = { + timeout: 1, + cb: function() {} + }; + operation.attempt(fn, timeoutOpts); + + assert.strictEqual(fn, operation._fn); + assert.strictEqual(timeoutOpts.timeout, operation._operationTimeout); + assert.strictEqual(timeoutOpts.cb, operation._operationTimeoutCb); +})(); + +(function testRetry() { + var times = 3; + var error = new Error('some error'); + var operation = retry.operation([1, 2, 3]); + var attempts = 0; + + var finalCallback = fake.callback('finalCallback'); + fake.expectAnytime(finalCallback); + + var fn = function() { + operation.attempt(function(currentAttempt) { + attempts++; + assert.equal(currentAttempt, attempts); + if (operation.retry(error)) { + return; + } + + assert.strictEqual(attempts, 4); + assert.strictEqual(operation.attempts(), attempts); + assert.strictEqual(operation.mainError(), error); + finalCallback(); + }); + }; + + fn(); +})();
\ No newline at end of file diff --git a/node_modules/npm-registry-client/node_modules/retry/test/integration/test-timeouts.js b/node_modules/npm-registry-client/node_modules/retry/test/integration/test-timeouts.js new file mode 100644 index 000000000..7206b0fb0 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/test/integration/test-timeouts.js @@ -0,0 +1,69 @@ +var common = require('../common'); +var assert = common.assert; +var retry = require(common.dir.lib + '/retry'); + +(function testDefaultValues() { + var timeouts = retry.timeouts(); + + assert.equal(timeouts.length, 10); + assert.equal(timeouts[0], 1000); + assert.equal(timeouts[1], 2000); + assert.equal(timeouts[2], 4000); +})(); + +(function testDefaultValuesWithRandomize() { + var minTimeout = 5000; + var timeouts = retry.timeouts({ + minTimeout: minTimeout, + randomize: true + }); + + assert.equal(timeouts.length, 10); + assert.ok(timeouts[0] > minTimeout); + assert.ok(timeouts[1] > timeouts[0]); + assert.ok(timeouts[2] > timeouts[1]); +})(); + +(function testPassedTimeoutsAreUsed() { + var timeoutsArray = [1000, 2000, 3000]; + var timeouts = retry.timeouts(timeoutsArray); + assert.deepEqual(timeouts, timeoutsArray); + assert.notStrictEqual(timeouts, timeoutsArray); +})(); + +(function testTimeoutsAreWithinBoundaries() { + var minTimeout = 1000; + var maxTimeout = 10000; + var timeouts = retry.timeouts({ + minTimeout: minTimeout, + maxTimeout: maxTimeout + }); + for (var i = 0; i < timeouts; i++) { + assert.ok(timeouts[i] >= minTimeout); + assert.ok(timeouts[i] <= maxTimeout); + } +})(); + +(function testTimeoutsAreIncremental() { + var timeouts = retry.timeouts(); + var lastTimeout = timeouts[0]; + for (var i = 0; i < timeouts; i++) { + assert.ok(timeouts[i] > lastTimeout); + lastTimeout = timeouts[i]; + } +})(); + +(function testTimeoutsAreIncrementalForFactorsLessThanOne() { + var timeouts = retry.timeouts({ + retries: 3, + factor: 0.5 + }); + + var expected = [250, 500, 1000]; + assert.deepEqual(expected, timeouts); +})(); + +(function testRetries() { + var timeouts = retry.timeouts({retries: 2}); + assert.strictEqual(timeouts.length, 2); +})(); diff --git a/node_modules/npm-registry-client/node_modules/retry/test/runner.js b/node_modules/npm-registry-client/node_modules/retry/test/runner.js new file mode 100644 index 000000000..e0ee2f570 --- /dev/null +++ b/node_modules/npm-registry-client/node_modules/retry/test/runner.js @@ -0,0 +1,5 @@ +var far = require('far').create(); + +far.add(__dirname); +far.include(/\/test-.*\.js$/); +far.execute(); |