У меня есть функция, которая обрабатывает несколько запросов API для меня и переводит каждый запрос в режим повтора, если не удается. Теперь, если один запрос уже находится в цикле повтора и поступает другой экземпляр того же вызова API, моя функция не может отследить это и снова добавить избыточный вызов API в цикл повторения.
Assuming i am placing a call to
/api/info/authors
What is happening
1stREQ| [re0]------>[re1]------>[re2]------>[re3]------>[re4]------>[re5]
2ndREQ| [re0]------>[re1]------>[re2]------>[re3]------>[re4]------>[re5]
What should happen,
1stREQ| [re0]------>[re1]------>[re2]------>[re3]------>[re4]------>[re5]
2ndREQ| [re0]/ (MERGE)
Послемой сервис совпадает с моей функцией Retry,
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { retryWhen, mergeMap, finalize, share, shareReplay } from 'rxjs/operators';
import { Observable, throwError, of, timer } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) { }
private apiUrl: string = 'http://localhost/api-slim-php/public/api';
public dataServerURL: string = 'http://localhost/';
/*
This function fetches all the info from API /info/{category}/{id}
category : author & id : '' or 1,2,3... or a,b,c...
category : form & id : '' or 1,2,3...
category : location & id : '' or 1,2,3...
category : school & id : '' or 1,2,3...
category : timeframe & id : '' or 1,2,3...
category : type & id : '' or 1,2,3...
*/
public getInfoAPI(category: string, id: string = "", page: string = "1", limit: string = "10") {
var callURL: string = '';
if (!!id.trim() && !isNaN(+id)) callURL = this.apiUrl + '/info/' + category + '/' + id;
else callURL = this.apiUrl + '/info/' + category;
return this.http.get(callURL, {
params: new HttpParams()
.set('page', page)
.set('limit', limit)
}).pipe(
retryWhen(genericRetryStrategy({ maxRetryAttempts: 5, scalingDuration: 1000 })),
shareReplay()
);
}
}
export const genericRetryStrategy = ({
maxRetryAttempts = 3,
scalingDuration = 1000,
excludedStatusCodes = []
}: {
maxRetryAttempts?: number,
scalingDuration?: number,
excludedStatusCodes?: number[]
} = {}) => (attempts: Observable<any>) => {
return attempts.pipe(
mergeMap((error, i) => {
const retryAttempt = i + 1;
// 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)
) {
console.log(error);
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!'))
);
};
Примечание:
Кто-то предложил около shareReplay()
, и я попытался реализовать его, но это былоне может обработать один и тот же запрос, сделанный двумя другими компонентами / источниками.
Следующим должно быть только 6, вместо этого они равны 12 при быстром нажатии двух кнопок, вызывающих один и тот же API (длительность масштабирования составляла 1000 мс).
ПРИМЕЧАНИЕ:
Пожалуйста, избегайте использования FLAGS
, по моему мнению, это последняя ядерная бомба.