问题
I use the concept of the backoff method to retry the request if internal Server Error occurs. I mean not 401
, 403
or similar. My target is to retry the request if the server doesn't respond and/or it takes too long to send a response, for instance in case of pending
status. And I do have defined timeout limit for that (in the service).
My Issue is that the retryWhen
function is being invoked in all the cases/errors including 401
.
I believe that I might have to restructure my function/code to make it work. I'm struggling with that, but just can't make it working as it expected.
The retryWhen
function returns an observable stream that indicates when to retry and therefore it can't work in my code as it should be.
public userLogin(userName, userPass: string) {
this.theService.login(userName, userPass)
.retryWhen(attempts => Observable.range(1, 3)
.zip(attempts, i => i)
.mergeMap(i => {
console.log("delay retry by " + i + " second(s)");
// Show a message to user to wait
if ( i === 3 ) {
// Show Server doesn't respond... try later
}
return Observable.timer(i * 3000);
})
).subscribe(
res => {
// handle and show response result
},
err => {
console.log(err);
if ( err === 401 ) {
// handle 401 error
} else {
// handle other error
}
}
);
}
The following question is also a kind of handling the same issue and I tried to use the hint regarding mergeMap(error => {...})
, but it didn't work for me.
Any idea please how I should restructure my code to retry the request just in case of internal server error or a kind of? as I mentioned no 401
, 403
or similar.
回答1:
You can re-throw the blacklisted errors in the retryWhen
operator as follows:
/**
* Performs a retry on an exponential backoff with an upper bounds.
* Will rethrow the error if it is in the blacklist or the retry
* attempts have exceeded the maximum.
* @param {number} initialDelay
* @param {number} maxRetry - maximum number of times to retry
* @param {number[]} errorWhiteList - whitelist of errors to retry on (non-transient)
*/
function expontentialRetry(
initialDelay,
maxRetry,
errorWhiteList
) {
return (errors) => errors.scan((retryAttempts, error) => {
if(!errorWhiteList.includes(error.status) || retryAttempts > maxRetry) {
throw error;
}
return retryAttempts + 1;
}, 0).switchMap((retryAttempts) => {
// calculate exponential backoff
let delay = Math.pow(2, retryAttempts - 1) * initialDelay;
console.log(`Retry attempt #${retryAttempts} in ${delay}ms`);
return Rx.Observable.timer(delay);
});
}
let count = 0;
const fakeApiCall = Rx.Observable.create((o) => {
if (count < 5) {
o.error({ status: 504 });
} else {
o.error({ status: 500 });
}
count++;
});
fakeApiCall.retryWhen(expontentialRetry(100, 10, [504]))
.subscribe(
(x) => { console.log('next', x); },
(error) => { console.log('error', error); },
() => { console.log('complete'); }
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.10/Rx.min.js"></script>
来源:https://stackoverflow.com/questions/50024524/how-to-handle-error-when-implementing-exponential-backoff-function