이번 글에서는 Health Check를 위한 React Router 확장법에 대해 설명 드리겠습니다. API 헬스 체크 방법에 대해서는 이전 글에서 살펴본 적이 있으니 아래 글을 참고하시길 바랍니다.
개발 시 Health Check 중요성
모든 애플리케이션은 다운타임에 대비하고 사용자에게 알리는 방식으로 대응해야 합니다. 따라서 애플리케이션은 애플리케이션의 백엔드가 다운되었을 때 일련의 조치를 취해야 합니다.
이를 수행하는 한 가지 방법은 사용자를 애플리케이션 다운 페이지로 리디렉션하는 것입니다. 또 다른 옵션은 애플리케이션 전체에서 이를 처리하는 것입니다. 이는 더 지루할 수 있지만 애플리케이션에 따라 올바른 접근 방식일 수 있습니다.
응용 프로그램 다운(404/500 오류) 페이지를 확장하여 사용자에게 다음 단계에 대한 자세한 정보를 제공할 수도 있습니다. 몇 분 동안 기다렸다가 다시 시도하거나, FAQ를 확인하거나 하는 방식으로 말이죠.
이번 글에서는 백엔드가 다운될 때 애플리케이션 다운 페이지로 라우팅할 수 있도록 반응 라우터에 대한 상태 확인을 설정하는 과정을 안내합니다. 백엔드 상태 API 호출과 같은 몇 가지 측면이 이미 설정되어 있다고 가정하겠습니다.
게이트웨이 구성 요소
반응 라우터에 상태 확인을 추가하기 위해 게이트웨이 구성 요소라는 것을 사용할 것입니다. 게이트웨이 구성 요소는 래핑된 구성 요소에 대한 게이트 역할을 합니다. 래핑된 구성 요소를 렌더링하기 전과 후에 추가 확인/처리를 수행할 수 있으므로 기존 구성 요소의 기능을 확장할 수 있습니다.
예를 들어 구성 요소는 응용 프로그램의 상태를 확인하고 사용자가 알 수 있도록 합니다. 응용 프로그램이 래핑된 구성 요소를 렌더링하는 것 외에 오프라인 모드에서 수행되고 있음을 알 수 있습니다. 이 예제에서는 간단하게 유지하기 위해 사용자를 애플리케이션 다운 페이지로 다시 라우팅합니다.
HealthCheckAndRoute 구성 요소
상태 확인 및 경로 구성 요소는 healthCheck 기능에 따라 다르므로 여기에 우리가 프로젝트를 위해 작성한 다음 기능이 있습니다. 이것은 구성 요소로 가져올 기능일 뿐이며 코드에는 다음과 같은 다른 모든 요구 사항이 포함되어 있지 않습니다.
export function checkHealth(): any { return (dispatch: Dispatch<IHealthState>, getState: () => IHealthState) => { dispatch(healthCheckRequest()) return api.checkHealth() .then((res: any) => { dispatch(healthCheckSuccess()) }) .catch((err: any) => { dispatch(healthCheckFailure()) history.push({ pathname: '/application/down' }) }) } }
다음 코드는 베어 본 HealthCheckAndRoute 게이트웨이 구성 요소로 반응 라우터와 동일한 기능을 수행합니다. 그런 다음 상태 확인을 적용하기 위해 수행해야 할 작업에 대해 논의합니다.
import * as React from 'react' import { connect } from 'react-redux' import { Route as OldRoute, RouteProps } from 'react-router-dom' class HealthCheckAndRoute extends React.Component<RouteProps> { constructor(props: RouteProps) { super(props) } public render() { return <OldRoute {…this.props} /> } } const Route = connect(null)(HealthCheckAndRoute) export default Route
위의 예에서 기본적으로 추가 기능이 없는 래퍼 구성 요소를 만들었고 HealthCheckAndRoute 구성 요소를 경로로 내보낼 수 있으므로 앱 페이지에서 가져오기 외에 변경할 필요가 없습니다. 그리고 나서 다음 단계를 수행해야 합니다.
- 구성 요소가 직면할 시나리오 파악
- 필요한 새 prop으로 RouteProps를 확장
- 상태 확인을 수행하고 해당 시나리오를 기반으로 다시 렌더링할 수명 주기 메서드를 추가
시나리오 예시
사용자는 모든 경로에서 애플리케이션을 방문하여 프런트엔드와 상호 작용할 수 있습니다. 이 시나리오에서는 일반 애플리케이션 페이지 또는 애플리케이션 다운 페이지의 두 가지 가능성으로 나뉩니다.
사용자가 방문하는 페이지에 관계없이 백엔드에는 두 가지 잠재적인 상태(죽음 또는 살아 있음)가 있습니다. 이로 인해 네 가지 잠재적인 시나리오가 발생합니다.
- 사용자가 일반 애플리케이션 경로를 방문하고 백엔드가 작동 (별도 작업 불필요)
- 사용자가 일반 애플리케이션 경로를 방문하고 백엔드가 다운됨 (애플리케이션 다운 페이지로 라우팅)
- 사용자가 애플리케이션 다운 페이지를 방문하고 백엔드가 작동 (사용자는 서비스가 활성 상태이고 홈페이지 등으로 다시 라우팅된다는 정보를 받아야 함)
- 사용자가 애플리케이션 다운 페이지를 방문하고 백엔드가 (별도 작업 불필요)
Route Props 확장
이제 시나리오를 알았으므로 코드를 다시 살펴보고 다음 단계로 넘어갑니다. Route props에는 반응 라우터에 필요한 모든 것이 포함되어 있지만 이제 결정을 내리려면 상태 확인 기능과 props의 백엔드 상태가 모두 필요합니다.
... interface IHealthCheckAndRouteProps extends RouteProps { applicationUp: boolean checkHealth(): any } class HealthCheckAndRoute extends React.Component<IHealthCheckAndRouteProps> { constructor(props: IHealthCheckAndRouteProps) { super(props) } ... } const mapStateToProps = (state: any) => { return { applicationUp: state.health.alive } } const Route = connect(mapStateToProps, { checkHealth })(HealthCheckAndRoute)
이제 props에 applicationUp 변수와 checkHealth 함수를 포함하도록 코드를 확장했습니다. 이를 사용하여 이제 수명 주기 정책을 정의하여 무엇을 렌더링해야 하는지 결정할 수 있습니다.
수명 주기 메서드 정의
이상적으로는 수명 주기 메서드를 정의할 필요가 없고 render() 메서드에서 상태 확인만 수행하면 됩니다. 메서드를 실행하고 .then을 사용하여 성공 사례를 처리하고 .catch를 사용하여 실패 사례를 처리합니다.
그러나 이것은 가능하지 않습니다 — 렌더링 방법의 특성으로 인해(저는 이것이 타이프스크립트 문제인지 일반적인 반응 문제인지 확실하지 않습니다). 상태 확인 메서드가 비동기이기 때문에 코드는 렌더링 전에 함수가 완료될 때까지 기다리지 않습니다. 따라서 다른 것이 렌더링되어야 하므로 수명 주기 메서드를 사용해야 합니다.
첫 번째 단계는 사용 사례에 필요한 수명 주기 방법을 결정하는 것입니다. render 메서드에서 상태 확인을 수행할 수 없기 때문입니다. 구성 요소가 마운트된 직후에 이 작업을 수행하려고 합니다. componentDidMount()가 첫 번째 수명 주기 메서드가 됩니다.
public componentDidMount() { this.props.checkHealth().then((res: any) => { if (this.props.path === '/application/down' && this.props.applicationUp) history.push({ pathname: '/application/home' }) }) }
우리는 checkHealth 호출을 호출하고 성공하고 애플리케이션/다운 페이지에 있으면 실패 페이지로 다시 라우팅해야 합니다. checkHealth가 실패하면 자동으로 다운 페이지로 다시 라우팅됩니다.
이 수명 주기 메서드는 한 번만 발생하므로 구성 요소의 소품이 변경될 때마다 하나 더 필요합니다. componentWillRecieveProps 메서드에서 동일한 논리를 구현할 것입니다.
public componentWillReceiveProps(newProps: any) { if (this.props.path !== newProps.path) { this.props.checkHealth().then((res: any) => { if (this.props.path === '/application/down' && this.props.applicationUp) history.push({ pathname: '/application/home' }) }) } }
이 모든 것의 끝에 존재하는 버그는 응용 프로그램이 다운되면 응용 프로그램 다운 페이지로 다시 전환하기 전에 깜박임을 알 수 있다는 것입니다. 구성 요소는 처음에 사용자가 탐색하려는 페이지를 렌더링한 다음 상태 확인을 수행하고 사용자를 애플리케이션 다운 페이지로 다시 라우팅합니다.