https://family-gram.tistory.com/603
REST API 호출 및 취소이후 API retry policy 관련
기존 API 코드
import axios, { AxiosRequestConfig, CancelTokenSource } from "axios";
const defaultConfig: AxiosRequestConfig = {};
const axiosApi = axios.create(defaultConfig);
type Executor<T> = (
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason?: any) => void
) => void;
export class ApiPromise<T> extends Promise<T> {
private $source: CancelTokenSource;
constructor(executor: Executor<T>, cancelSource: CancelTokenSource) {
super(executor);
this.$source = cancelSource;
}
public cancel(msg?: string) {
this.$source.cancel(msg);
}
get source(): CancelTokenSource {
return this.$source;
}
}
class Service {
get(url: string, params?: { [key: string]: string | number }): ApiPromise<any> {
const cancelSource = axios.CancelToken.source();
const api = axiosApi.get(url, {
params: params,
cancelToken: cancelSource.token,
});
return new ApiPromise((resolve, reject) => {
api.then((resp) => {
resolve(resp);
}).catch((error) => {
reject(error);
});
}, cancelSource);
}
}
yarn add rxjs
Rx ( ReactiveX ) 는 RxJs, RxJava, Rx... 많은 언어에 해당하는 라이브러리가 있다. 사용언어에 따라 표현법은 조금씩 다르나 개념은 동일하니 알아두면 다른언어에서도 사용가능하다
Javascript 경우에는 UI에서 Background thread pool 이 따로 없기 때문에 subscriptionOn 이나 observeOn 같은 API 가 없는듯 하다
코드 업데이트
import axios, { AxiosRequestConfig, CancelTokenSource } from "axios";
// 추가
import { concatMap, delay, mergeMap, of, retryWhen, take, tap, throwError } from "rxjs";
const defaultConfig: AxiosRequestConfig = {};
const axiosApi = axios.create(defaultConfig);
// 추가
const RETRY_COUNT = 2;
const onGlobalError = (error: any) => {
console.debug("ERROR !", error);
};
type Executor<T> = (
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason?: any) => void
) => void;
export class ApiPromise<T> extends Promise<T> {
private $source: CancelTokenSource;
constructor(executor: Executor<T>, cancelSource: CancelTokenSource) {
super(executor);
this.$source = cancelSource;
}
public cancel(msg?: string) {
this.$source.cancel(msg || "Cancel");
}
get source(): CancelTokenSource {
return this.$source;
}
}
class Service {
get(url: string, params?: { [key: string]: string | number }): ApiPromise<any> {
const cancelSource = axios.CancelToken.source();
const data = {
url: url,
data: {
params: params,
cancelToken: cancelSource.token,
},
};
return new ApiPromise((resolve, reject) => {
const onSuccesed = (resp: any) => {
resolve(resp);
};
const onError = (error: any) => {
reject(error);
};
of(data)
.pipe(
concatMap((e) => axiosApi.get(e.url, e.data)),
tap({
error: onGlobalError,
}),
retryWhen((errors) =>
errors.pipe(
mergeMap((error) => {
const { response } = error;
if (response && response.status) {
const { status } = response;
if (status >= 500) {
return of(status).pipe(delay(1000));
}
}
return throwError(() => error);
}),
take(RETRY_COUNT)
)
)
)
.subscribe({
next: onSuccesed,
error: onError,
});
}, cancelSource);
}
}
API 요청 실패 시, status를 확인하여 재요청 여부를 체크
const onSuccesed = (resp: any) => {
resolve(resp);
};
const onError = (error: any) => {
reject(error);
};
of(data)
.pipe(
concatMap((e) => axiosApi.get(e.url, e.data)),
tap({
error: onGlobalError,
}),
retryWhen((errors) =>
errors.pipe(
mergeMap((error) => {
const { response } = error;
if (response && response.status) {
const { status } = response;
if (status >= 500) {
return of(status).pipe(delay(1000));
}
}
return throwError(() => error);
}),
take(RETRY_COUNT)
)
)
)
.subscribe({
next: onSuccesed,
error: onError,
});
최초 응답이 실패했을 경우 retryWhen 에서 response 의 status 를 확인하여 재요청 여부를 체크한다. 500대 이상 에러의 경우는 재요청.
재요청 상황
기존 promise 인 api 를 RxJs의 of을 이용하여 Observable 형태로 변환한다.
pipe - tap 을 통해 요청하는 모든 에러에 대해서 onGlobalError function 으로 체크한다.
pipe - retryWhen retry 조건을 파악하여 요청이 필요한 경우 delay 형태의 Observable 을 반환, take를 이용하여 재요청 카운트 확인
에러요청을 체크하는 onGlobalError 는 retryWhen 이전에 정의되어야함
'개발 > React' 카테고리의 다른 글
React Scripts 4.x -> 5.x 마이그레이션 (0) | 2023.10.26 |
---|---|
React Chunk hash를 제거 해보자 (0) | 2022.04.15 |
axios 를 이용한 REST API 호출 및 취소 (0) | 2021.09.26 |
react-script 업데이트 IE11 동작하지 않는 문제 (0) | 2020.09.18 |
React 에서 jest 를 이용한 API test 시 timeout 변경 (0) | 2020.09.18 |