init source
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2015-2016 Mick Hansen. http://mhansen.io
|
||||
|
||||
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.
|
||||
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
# retry-as-promised
|
||||
|
||||
Retry promises when they fail, based upon [any-promise](https://github.com/kevinbeaty/any-promise).
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ npm install --save retry-as-promised
|
||||
$ yarn add retry-as-promised
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
```js
|
||||
var retry = require('retry-as-promised');
|
||||
|
||||
var warningFn = function(msg){ someLoggingFunction(msg, 'notice'); };
|
||||
|
||||
// Will call the until max retries or the promise is resolved.
|
||||
return retry(function (options) {
|
||||
// options.current, times callback has been called including this call
|
||||
return promise;
|
||||
}, {
|
||||
max: 3, // maximum amount of tries
|
||||
timeout: 10000 // throw if no response or error within millisecond timeout, default: undefined,
|
||||
match: [ // Must match error signature (ala bluebird catch) to continue
|
||||
Sequelize.ConnectionError,
|
||||
'SQLITE_BUSY'
|
||||
],
|
||||
backoffBase: 1000 // Initial backoff duration in ms. Default: 100,
|
||||
backoffExponent: 1.5 // Exponent to increase backoff each try. Default: 1.1
|
||||
report: warningFn, // the function used for reporting; must have a (string, object) argument signature, where string is the message that will passed in by retry-as-promised, and the object will be this configuration object + the $current property
|
||||
name: 'SourceX' // if user supplies string, it will be used when composing error/reporting messages; else if retry gets a callback, uses callback name in erroring/reporting; else (default) uses literal string 'unknown'
|
||||
});
|
||||
```
|
||||
|
||||
## Tested with
|
||||
|
||||
- Bluebird
|
||||
- Q
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
|
||||
var Promise = require('any-promise');
|
||||
var util = require('util');
|
||||
var format = util.format;
|
||||
|
||||
function TimeoutError(message, err) {
|
||||
Error.call(this);
|
||||
Error.captureStackTrace(this, TimeoutError);
|
||||
this.name = 'TimeoutError';
|
||||
this.message = message;
|
||||
this.previous = err;
|
||||
}
|
||||
|
||||
util.inherits(TimeoutError, Error);
|
||||
|
||||
function matches(match, err) {
|
||||
if (match === true) return true;
|
||||
if (typeof match === 'function') {
|
||||
try {
|
||||
if (err instanceof match) return true;
|
||||
} catch (_) {
|
||||
return !!match(err);
|
||||
}
|
||||
}
|
||||
if (match === err.toString()) return true;
|
||||
if (match === err.message) return true;
|
||||
return match instanceof RegExp
|
||||
&& (match.test(err.message) || match.test(err.toString()));
|
||||
}
|
||||
|
||||
module.exports = function retryAsPromised(callback, options) {
|
||||
if (!callback || !options) {
|
||||
throw new Error(
|
||||
'retry-as-promised must be passed a callback and a options set or a number'
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof options === 'number') {
|
||||
options = {
|
||||
max: options
|
||||
};
|
||||
}
|
||||
|
||||
// Super cheap clone
|
||||
options = {
|
||||
$current: options.$current || 1,
|
||||
max: options.max,
|
||||
timeout: options.timeout || undefined,
|
||||
match: options.match || [],
|
||||
backoffBase: options.backoffBase === undefined ? 100 : options.backoffBase,
|
||||
backoffExponent: options.backoffExponent || 1.1,
|
||||
report: options.report || function () {},
|
||||
name: options.name || callback.name || 'unknown'
|
||||
};
|
||||
|
||||
if (!Array.isArray(options.match)) options.match = [options.match];
|
||||
options.report('Trying ' + options.name + ' #' + options.$current + ' at ' + new Date().toLocaleTimeString(), options);
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
var timeout, backoffTimeout, lastError;
|
||||
|
||||
if (options.timeout) {
|
||||
timeout = setTimeout(function() {
|
||||
if (backoffTimeout) clearTimeout(backoffTimeout);
|
||||
reject(new TimeoutError(options.name + ' timed out', lastError));
|
||||
}, options.timeout);
|
||||
}
|
||||
|
||||
Promise.resolve(callback({ current: options.$current }))
|
||||
.then(resolve)
|
||||
.then(function() {
|
||||
if (timeout) clearTimeout(timeout);
|
||||
if (backoffTimeout) clearTimeout(backoffTimeout);
|
||||
})
|
||||
.catch(function(err) {
|
||||
if (timeout) clearTimeout(timeout);
|
||||
if (backoffTimeout) clearTimeout(backoffTimeout);
|
||||
|
||||
lastError = err;
|
||||
options.report((err && err.toString()) || err, options);
|
||||
|
||||
// Should not retry if max has been reached
|
||||
var shouldRetry = options.$current < options.max;
|
||||
if (!shouldRetry) return reject(err);
|
||||
shouldRetry = options.match.length === 0 || options.match.some(function (match) {
|
||||
return matches(match, err)
|
||||
});
|
||||
if (!shouldRetry) return reject(err);
|
||||
|
||||
var retryDelay = Math.pow(
|
||||
options.backoffBase,
|
||||
Math.pow(options.backoffExponent, options.$current - 1)
|
||||
);
|
||||
|
||||
// Do some accounting
|
||||
options.$current++;
|
||||
options.report(format('Retrying %s (%s)', options.name, options.$current), options);
|
||||
|
||||
if (retryDelay) {
|
||||
// Use backoff function to ease retry rate
|
||||
options.report(format('Delaying retry of %s by %s', options.name, retryDelay), options);
|
||||
backoffTimeout = setTimeout(function() {
|
||||
retryAsPromised(callback, options)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
}, retryDelay);
|
||||
} else {
|
||||
retryAsPromised(callback, options)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.TimeoutError = TimeoutError;
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"retry-as-promised@3.2.0",
|
||||
"/home/app"
|
||||
]
|
||||
],
|
||||
"_from": "retry-as-promised@3.2.0",
|
||||
"_id": "retry-as-promised@3.2.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==",
|
||||
"_location": "/retry-as-promised",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "retry-as-promised@3.2.0",
|
||||
"name": "retry-as-promised",
|
||||
"escapedName": "retry-as-promised",
|
||||
"rawSpec": "3.2.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "3.2.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/sequelize"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz",
|
||||
"_spec": "3.2.0",
|
||||
"_where": "/home/app",
|
||||
"author": {
|
||||
"name": "Mick Hansen",
|
||||
"email": "maker@mhansen.io"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/mickhansen/retry-as-promised/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"any-promise": "^1.3.0"
|
||||
},
|
||||
"description": "Retry a failed promise",
|
||||
"devDependencies": {
|
||||
"bluebird": "^3.5.1",
|
||||
"chai": "^4.2.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"cross-env": "^5.2.0",
|
||||
"mocha": "^5.2.0",
|
||||
"moment": "^2.10.6",
|
||||
"q": "^1.5.1",
|
||||
"sinon": "^7.0.0",
|
||||
"sinon-chai": "^3.2.0"
|
||||
},
|
||||
"files": [],
|
||||
"homepage": "https://github.com/mickhansen/retry-as-promised",
|
||||
"keywords": [
|
||||
"retry",
|
||||
"promise",
|
||||
"bluebird"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"name": "retry-as-promised",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/mickhansen/retry-as-promised.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "PROMISE_TYPE=bluebird npm run test-raw && PROMISE_TYPE=q npm run test-raw",
|
||||
"test-raw": "cross-env DEBUG=retry-as-promised* ./node_modules/.bin/mocha --check-leaks --colors -t 10000 --reporter spec test/promise.test.js"
|
||||
},
|
||||
"version": "3.2.0"
|
||||
}
|
||||
Reference in New Issue
Block a user