Projekt

Obecné

Profil

Stáhnout (5.31 KB) Statistiky
| Větev: | Revize:
1
'use strict';
2

    
3
Object.defineProperty(exports, "__esModule", {
4
    value: true
5
});
6
exports.default = retry;
7

    
8
var _noop = require('lodash/noop');
9

    
10
var _noop2 = _interopRequireDefault(_noop);
11

    
12
var _constant = require('lodash/constant');
13

    
14
var _constant2 = _interopRequireDefault(_constant);
15

    
16
var _wrapAsync = require('./internal/wrapAsync');
17

    
18
var _wrapAsync2 = _interopRequireDefault(_wrapAsync);
19

    
20
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21

    
22
/**
23
 * Attempts to get a successful response from `task` no more than `times` times
24
 * before returning an error. If the task is successful, the `callback` will be
25
 * passed the result of the successful task. If all attempts fail, the callback
26
 * will be passed the error and result (if any) of the final attempt.
27
 *
28
 * @name retry
29
 * @static
30
 * @memberOf module:ControlFlow
31
 * @method
32
 * @category Control Flow
33
 * @see [async.retryable]{@link module:ControlFlow.retryable}
34
 * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - Can be either an
35
 * object with `times` and `interval` or a number.
36
 * * `times` - The number of attempts to make before giving up.  The default
37
 *   is `5`.
38
 * * `interval` - The time to wait between retries, in milliseconds.  The
39
 *   default is `0`. The interval may also be specified as a function of the
40
 *   retry count (see example).
41
 * * `errorFilter` - An optional synchronous function that is invoked on
42
 *   erroneous result. If it returns `true` the retry attempts will continue;
43
 *   if the function returns `false` the retry flow is aborted with the current
44
 *   attempt's error and result being returned to the final callback.
45
 *   Invoked with (err).
46
 * * If `opts` is a number, the number specifies the number of times to retry,
47
 *   with the default interval of `0`.
48
 * @param {AsyncFunction} task - An async function to retry.
49
 * Invoked with (callback).
50
 * @param {Function} [callback] - An optional callback which is called when the
51
 * task has succeeded, or after the final failed attempt. It receives the `err`
52
 * and `result` arguments of the last attempt at completing the `task`. Invoked
53
 * with (err, results).
54
 *
55
 * @example
56
 *
57
 * // The `retry` function can be used as a stand-alone control flow by passing
58
 * // a callback, as shown below:
59
 *
60
 * // try calling apiMethod 3 times
61
 * async.retry(3, apiMethod, function(err, result) {
62
 *     // do something with the result
63
 * });
64
 *
65
 * // try calling apiMethod 3 times, waiting 200 ms between each retry
66
 * async.retry({times: 3, interval: 200}, apiMethod, function(err, result) {
67
 *     // do something with the result
68
 * });
69
 *
70
 * // try calling apiMethod 10 times with exponential backoff
71
 * // (i.e. intervals of 100, 200, 400, 800, 1600, ... milliseconds)
72
 * async.retry({
73
 *   times: 10,
74
 *   interval: function(retryCount) {
75
 *     return 50 * Math.pow(2, retryCount);
76
 *   }
77
 * }, apiMethod, function(err, result) {
78
 *     // do something with the result
79
 * });
80
 *
81
 * // try calling apiMethod the default 5 times no delay between each retry
82
 * async.retry(apiMethod, function(err, result) {
83
 *     // do something with the result
84
 * });
85
 *
86
 * // try calling apiMethod only when error condition satisfies, all other
87
 * // errors will abort the retry control flow and return to final callback
88
 * async.retry({
89
 *   errorFilter: function(err) {
90
 *     return err.message === 'Temporary error'; // only retry on a specific error
91
 *   }
92
 * }, apiMethod, function(err, result) {
93
 *     // do something with the result
94
 * });
95
 *
96
 * // to retry individual methods that are not as reliable within other
97
 * // control flow functions, use the `retryable` wrapper:
98
 * async.auto({
99
 *     users: api.getUsers.bind(api),
100
 *     payments: async.retryable(3, api.getPayments.bind(api))
101
 * }, function(err, results) {
102
 *     // do something with the results
103
 * });
104
 *
105
 */
106
function retry(opts, task, callback) {
107
    var DEFAULT_TIMES = 5;
108
    var DEFAULT_INTERVAL = 0;
109

    
110
    var options = {
111
        times: DEFAULT_TIMES,
112
        intervalFunc: (0, _constant2.default)(DEFAULT_INTERVAL)
113
    };
114

    
115
    function parseTimes(acc, t) {
116
        if (typeof t === 'object') {
117
            acc.times = +t.times || DEFAULT_TIMES;
118

    
119
            acc.intervalFunc = typeof t.interval === 'function' ? t.interval : (0, _constant2.default)(+t.interval || DEFAULT_INTERVAL);
120

    
121
            acc.errorFilter = t.errorFilter;
122
        } else if (typeof t === 'number' || typeof t === 'string') {
123
            acc.times = +t || DEFAULT_TIMES;
124
        } else {
125
            throw new Error("Invalid arguments for async.retry");
126
        }
127
    }
128

    
129
    if (arguments.length < 3 && typeof opts === 'function') {
130
        callback = task || _noop2.default;
131
        task = opts;
132
    } else {
133
        parseTimes(options, opts);
134
        callback = callback || _noop2.default;
135
    }
136

    
137
    if (typeof task !== 'function') {
138
        throw new Error("Invalid arguments for async.retry");
139
    }
140

    
141
    var _task = (0, _wrapAsync2.default)(task);
142

    
143
    var attempt = 1;
144
    function retryAttempt() {
145
        _task(function (err) {
146
            if (err && attempt++ < options.times && (typeof options.errorFilter != 'function' || options.errorFilter(err))) {
147
                setTimeout(retryAttempt, options.intervalFunc(attempt));
148
            } else {
149
                callback.apply(null, arguments);
150
            }
151
        });
152
    }
153

    
154
    retryAttempt();
155
}
156
module.exports = exports['default'];
(83-83/105)