Я думаю, что пример, приведенный в документации, написан для Observable, который испускает только один раз, а затем завершается, например, http get. Предполагается, что если вы хотите получить больше данных, вы снова подпишетесь, что обнулит счетчик внутри genericRetryStrategy
. Однако если теперь вы хотите применить эту же стратегию к долговременной наблюдаемой, поток которой не будет завершен, если она не выдаст ошибку (например, у вас с interval()
), вам нужно будет изменить genericRetryStrategy()
чтобы узнать, когда необходимо сбросить счетчик.
Это можно сделать несколькими способами, я привел простой пример в этом StackBlitz , основанном на том, что, как вы сказали, пыталисьвыполнить. Обратите внимание, что я также немного изменил вашу логику, чтобы она больше соответствовала тому, что, как вы сказали, вы пытались сделать, - это «2 успешных попытки и затем 2 неудачных попытки». Однако важные биты модифицируют объект ошибки, который добавляется в genericRetryStrategy()
, чтобы сообщить текущее число неудачных попыток, чтобы он мог реагировать соответствующим образом.
Вот код, скопированный здесь для полноты:
import { timer, interval, Observable, throwError } from 'rxjs';
import { map, switchMap, tap, retryWhen, delayWhen, mergeMap, shareReplay, finalize, catchError } from 'rxjs/operators';
console.clear();
interface Err {
status?: number;
msg?: string;
int: number;
}
export const genericRetryStrategy = ({
maxRetryAttempts = 3,
scalingDuration = 1000,
excludedStatusCodes = []
}: {
maxRetryAttempts?: number,
scalingDuration?: number,
excludedStatusCodes?: number[]
} = {}) => (attempts: Observable<any>) => {
return attempts.pipe(
mergeMap((error: Err) => {
// i here does not reset and continues to increment?
const retryAttempt = error.int;
// if maximum number of retries have been met
// or response is a status code we don't wish to retry, throw error
if (
retryAttempt > maxRetryAttempts ||
excludedStatusCodes.find(e => e === error.status)
) {
return throwError(error);
}
console.log(
`Attempt ${retryAttempt}: retrying in ${retryAttempt *
scalingDuration}ms`
);
// retry after 1s, 2s, etc...
return timer(retryAttempt * scalingDuration);
}),
finalize(() => console.log('We are done!'))
);
};
let int = 0;
let err: Err = {int: 0};
//emit value every 1s
interval(1000).pipe(
map((val) => {
if (val > 1) {
//error will be picked up by retryWhen
int++;
err.msg = "equals 1";
err.int = int;
throw err;
}
if (val === 0 && int === 1) {
err.msg = "greater than 2";
err.int = 2;
int=0;
throw err;
}
return val;
}),
retryWhen(genericRetryStrategy({
maxRetryAttempts: 3,
scalingDuration: 1000,
excludedStatusCodes: [],
}))
).subscribe(val => {
console.log(val)
});
Для меня это все еще очень важно, но без понимания проблемы, которую вы пытаетесь решить более глубоко, я не могу сейчас придумать более декларативный подход ...