플러팅 AI/React-native

React Native 앱에서 Google Cloud Run 서버 초기화 및 WebSocket 안정화 해결

Solo.dev 2024. 12. 2. 02:18

 

문제 상황

  • 앱 초기 실행 시 WebSocket 연결 문제: Google Cloud Run에 배포된 서버가 꺼진 상태에서는 WebSocket connect 이벤트가 동작하지 않음.
  • SID 미수신: 앱에서 WebSocket으로 SID를 받아야 하는데, 서버가 꺼져 있으면 이를 받을 수 없어 정상적인 동작이 불가능.
  • 사용자 경험 문제: 서버가 꺼진 상태에서 첫 사용자는 어플을 다시 껐다 켜야 SID를 받을 수 있음.

해결 방법

  1. 앱 초기 진입점에서 서버 상태 확인
    • 앱 시작 시 HTTP 요청으로 Google Cloud Run 서버의 /health 엔드포인트에 상태 확인 요청을 보냄.
    • 서버가 꺼져 있다면, 이 요청을 통해 서버가 자동으로 시작됨(Google Cloud Run은 첫 요청 시 컨테이너를 활성화).
  2. Splash Screen 유지
    • 서버 상태가 OK 응답을 반환할 때까지 Splash Screen을 유지.
    • 서버 준비 완료 후, WebSocket 연결을 시도하여 SID를 받고 다음 화면으로 이동.
  3. 로직 통합
    • HTTP로 서버 활성화 확인 + WebSocket 연결 상태를 통합하여 앱 준비 상태 관리.
    • 서버가 준비되기 전에 WebSocket 이벤트가 실패하지 않도록 순서를 조정.

구현 결과

  1. 앱 실행 시 HTTP로 서버의 /health 엔드포인트 호출.
  2. 서버 준비 완료 후 WebSocket connect 이벤트 동작.
    • WebSocket 연결 성공 시 SID를 정상적으로 수신.
  3. Splash Screen이 사라지고 로그인 화면으로 이동.
  4. 테스트 결과 첫 사용자도 정상적으로 동작.

요약 코드

useEffect(() => {
    // 서버 활성화 확인 로직
    const checkServer = async () => {
        for (let attempt = 1; attempt <= 5; attempt++) {
            try {
                console.log(`Checking server (Attempt ${attempt}/5)`);
                const response = await fetch(`${FLASK_SERVER_URL}/health`);
                if (response.ok) {
                    setIsServerReady(true); // 서버 준비 완료
                    return;
                }
            } catch (error) {
                console.error(`Failed attempt ${attempt}:`, error);
            }
            if (attempt < 5) await new Promise(resolve => setTimeout(resolve, 2000)); // 재시도 딜레이
        }
        console.error('Server not available after retries');
    };

    checkServer();
}, [FLASK_SERVER_URL]);

useEffect(() => {
    // 앱 준비 상태 확인
    if (isServerReady && isSocketConnected) {
        setIsAppReady(true);
    }
}, [isServerReady, isSocketConnected]);

최종 결과

  • 첫 사용자도 앱 실행 시 Splash Screen에서 서버 상태를 확인한 후 정상 동작.
  • WebSocket 연결 및 SID 수신이 안정적으로 이루어짐.
  • 앱 초기 로딩 경험이 개선됨.