-
Notifications
You must be signed in to change notification settings - Fork 4
/
error-retry.ts
111 lines (100 loc) · 3.4 KB
/
error-retry.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// @ts-ignore
import { XiorError, delay } from 'xior/utils';
import { XiorInterceptorRequestConfig, XiorPlugin, XiorRequestConfig } from '../types';
export type ErrorRetryOptions = {
/** retry times, default: 2 */
retryTimes?: number;
/**
* Retry after milliseconds, default: 3000
* after first time error retry, retry interval
*/
retryInterval?:
| number
| ((count: number, config: XiorInterceptorRequestConfig, error: XiorError) => number);
/**
* default: true,
* it's useful because we don't want retry when the error because of token expired
*/
enableRetry?: boolean | ((config: XiorRequestConfig, error: XiorError) => boolean | undefined);
onRetry?: (config: XiorRequestConfig, error: XiorError, count: number) => void;
};
/** @ts-ignore */
declare module 'xior' {
interface XiorRequestConfig extends ErrorRetryOptions {}
}
export default function xiorErrorRetryPlugin(options: ErrorRetryOptions = {}): XiorPlugin {
const {
retryTimes: _retryTimes,
retryInterval: _retryInterval,
enableRetry: _enableRetry,
onRetry: _onRetry,
} = {
...{
retryTimes: 2,
retryInterval: 3000,
},
...(options || {}),
};
return function (adapter, instance) {
return async (config) => {
const {
retryTimes = _retryTimes,
retryInterval = _retryInterval,
enableRetry = _enableRetry,
onRetry = _onRetry,
} = config as ErrorRetryOptions;
let timeUp = false;
let count = 0;
async function handleRequest(isRetry = false) {
if (isRetry && instance?.REQI) {
for (const item of instance.REQI) {
config = await item(config as XiorInterceptorRequestConfig);
}
}
try {
let promise = adapter(config);
let i = 0;
const responseInterceptorChain: any[] = [];
instance?.RESI.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fn, interceptor.onRejected);
});
while (responseInterceptorChain.length > i) {
promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);
}
config._RESIRun = true;
return await promise;
} catch (error) {
const isGet = config.method === 'GET' || Boolean(config.isGet);
const t = typeof enableRetry;
let enabled: boolean | undefined = undefined;
if (t === 'function') {
enabled = (
enableRetry as (
config: XiorRequestConfig,
error: XiorError | Error
) => boolean | undefined
)(config, error as XiorError);
}
if (enabled === undefined) {
enabled = t === 'undefined' ? isGet : Boolean(enableRetry);
}
timeUp = retryTimes === count;
if (timeUp || !enabled) {
throw error;
}
const delayTime =
typeof retryInterval === 'function'
? retryInterval(count, config as XiorInterceptorRequestConfig, error as XiorError)
: retryInterval;
if (delayTime && delayTime > 0 && count > 0) {
await delay(delayTime);
}
count++;
if (onRetry) onRetry(config, error as XiorError, count);
return handleRequest(true);
}
}
return handleRequest();
};
};
}