Skip to main content

React Native 0.71-RC0 Android 장애 사후 분석

· 14 min read
Nicola Corti
Nicola Corti
Software Engineer at Meta
Lorenzo Sciandra
Lorenzo Sciandra
Senior Software Engineer at Microsoft

이제 0.71 버전이 공개되었으므로, 2022년 11월 4일 React Native와 Expo의 첫 0.71 릴리스 후보를 출시하면서 발생한 Android 빌드 문제에 대한 주요 정보를 공유하려 한다.

이 문제를 해결하는 데 기여한 개발자들은 최근 사후 분석 회의에 참여해 발생한 일, 이를 통해 배운 점, 그리고 앞으로 유사한 장애를 방지하기 위해 취할 조치에 대해 자세히 논의했다.

어떤 일이 있었나​

2022년 11월 4일, 우리는 React Native의 0.71.0-rc0 버전을 여러 공개 저장소에 출시했다. 이 버전은 0.71의 첫 번째 릴리스 후보였다.

이 릴리스 후보에서 주요 변경 사항은 소스 코드에서 빌드하는 대신 Maven Central에 아티팩트를 게시해 빌드 시간을 개선한 것이다. 이 작업이 어떻게 진행되었는지에 대한 자세한 내용은 RFC#508과 관련 논의에서 확인할 수 있다.

하지만 새로운 프로젝트를 템플릿에서 스캐폴딩하는 방식 때문에, 이전 버전을 사용하는 모든 Android 사용자에게 빌드 실패가 발생했다. 그들은 프로젝트에서 사용 중인 버전(예: 0.68.0) 대신 0.71.0-rc0의 새로운 아티팩트를 다운로드하기 시작했기 때문이다.

왜 이런 일이 발생했는가​

React Native 템플릿은 안드로이드 앱을 빌드하기 위해 build.gradle 파일을 제공한다. 이 파일은 React Native 안드로이드 라이브러리에 대한 의존성을 포함하고 있으며, 다음과 같이 표현된다: implementation("com.facebook.react:react-native:+").

여기서 중요한 점은 이 의존성의 + 부분(Gradle 동적 버전)이 Gradle에게 React Native의 최신 버전을 선택하도록 지시한다는 것이다. Gradle 동적 버전을 사용하는 것은 재현 가능성이 낮은 빌드를 초래할 수 있으므로 안티패턴으로 간주된다.

우리는 동적 버전이 야기할 수 있는 문제를 인지하고 있었기 때문에, 0.71 버전에서 새로운 앱 템플릿을 정리하고 모든 + 의존성을 제거했다. 그러나 이전 버전의 React Native를 사용하는 사용자들은 여전히 + 버전을 사용하고 있었다.

이로 인해 0.71.0-rc.0 이전 버전의 React Native를 사용하는 빌드가 모든 리포지토리를 쿼리하여 React Native의 최신 버전을 찾게 되었다. Maven Central에 새로 푸시된 0.71.0-rc.0이 사용 가능한 최신 버전이 되었기 때문에, 0.71.0-rc.0 이전 버전의 React Native를 사용하는 빌드들이 0.71.0-rc.0의 아티팩트를 사용하기 시작했다. 로컬 빌드(예: 0.68.0)와 Maven Central의 아티팩트(0.71.0-rc.0) 간의 React Native 버전 불일치로 인해 이러한 빌드들이 실패하게 되었다.

이 이벤트에 대한 추가 기술적 세부 사항은 이 GitHub 이슈에서도 확인할 수 있다.

문제 해결 과정​

11월 4일 문제를 확인한 직후, 커뮤니티에서 수동으로 문제를 해결하는 방법을 찾아 공유했다. 이 방법은 React Native를 특정 버전으로 고정해 문제를 해결하는 방식이었다.

11월 5일과 6일 주말 동안, 릴리스 팀은 React Native 0.63 버전까지 모든 이전 버전에 대한 패치 릴리스를 배포했다. 이 패치가 자동으로 적용되어 사용자들이 수정된 React Native 버전으로 업데이트할 수 있게 했다.

동시에, Sonatype에 연락해 문제가 되는 아티팩트를 제거해 줄 것을 요청했다.

11월 8일, Maven Central에서 아티팩트가 완전히 제거되면서 이슈가 완전히 해결됐다.

주요 이벤트 타임라인​

이 섹션에서는 주요 이벤트의 타임라인을 정리한다. 모든 시간은 GMT/UTC +0 기준이다.

교훈​

이번 사건을 유발한 조건들은 React Native 0.12.0 버전부터 존재해 왔지만, 앞으로 React Native를 개발하고 출시하는 데 더 튼튼한 기반을 마련하고자 한다. 이번 경험을 통해 얻은 교훈과 앞으로 프로세스와 인프라를 어떻게 개선할지에 대한 실행 계획을 공유한다. 이를 통해 더 빠르고 강력하게 대응할 수 있도록 할 것이다.

인시던트 대응 전략​

이번 사건은 React Native와 관련된 오픈소스 문제에 대한 우리의 인시던트 대응 전략의 허점을 드러냈다.

커뮤니티는 불과 2시간 만에 임시 해결책을 찾았다. 이 문제의 영향 범위에 대한 우리의 가시성 부족과 구버전에서의 수정이 복잡하다는 점 때문에, 우리는 GitHub 이슈에서 임시 해결책을 찾는 데 의존할 수밖에 없었다.

이 문제의 더 큰 범위를 인식하고 모든 사람이 GitHub 이슈를 찾을 수 있다고 기대할 수 없다는 사실을 깨닫는 데 48시간이 걸렸다. 우리는 사람들의 프로젝트를 자동으로 수정하기 위해 더 복잡한 적극적인 완화 조치를 우선적으로 적용해야 했다.

앞으로 개발자가 직접 적용하는 임시 해결책과 자동으로 배포할 수 있는 수정 사항 중 어떤 것을 선택할지에 대한 프로세스를 재검토할 예정이다. 또한 우리 생태계의 상태를 더 잘 파악할 수 있는 방법도 살펴볼 것이다.

릴리즈 지원 정책​

rn-versions 도구에서 확인할 수 있듯이, 사건 당시 React Native 개발자 기반의 90% 이상을 커버하기 위해 버전 0.63까지 패치를 릴리즈해야 했다.

이 문제는 React Native 업그레이드 경험이 역사적으로 많은 마찰을 겪어왔기 때문에 발생한 것으로 보인다. 현재 생태계의 파편화를 완화하고 업그레이드 경험을 더 부드럽고 빠르게 개선할 방법을 모색 중이다.

새로운 버전의 React Native를 릴리즈하더라도 이전 버전을 사용 중인 사용자에게 영향을 미쳐서는 안 된다. 이번 사건으로 여러분의 업무 흐름에 방해가 된 점에 대해 사과의 말씀을 전한다.

동시에, 최신 버전의 의존성과 React Native를 사용하는 것의 중요성을 강조하고 싶다. 이를 통해 우리가 도입한 개선 사항과 안전 장치를 활용할 수 있다. 이 사건은 공식 릴리즈 지원 정책이 정의되고 있던 시점에 발생했으며, 아직 공개되거나 강제되지 않은 상태였다.

앞으로는 지원 정책을 커뮤니케이션 채널을 통해 명확히 전달할 예정이다. 또한 npm에서 이전 버전의 React Native를 더 이상 사용하지 않도록(deprecating) 하는 것도 고려 중이다.

타사 라이브러리 테스트 개선 및 모범 사례​

이번 사건은 릴리스 테스트를 강화하고 타사 라이브러리에 대한 더 나은 가이드를 제공하는 것이 얼마나 중요한지 다시 한번 강조했다.

테스트 측면에서 0.63.x 버전까지의 릴리스는 현재 안정 버전에 적용된 자동화와 테스트가 부족해 어려움을 겪었다. 우리는 릴리스와 테스트 인프라의 중요성을 인지하고 있으며, 앞으로 이 부분에 더 많은 투자를 할 계획이다.

구체적으로, React Native 릴리스의 일환으로 타사 라이브러리 테스트를 적극 권장하고 지원하고 있다. 또한 Core Contributors Discord Server에 새로운 채널과 역할을 추가했다.

이와 함께, create-react-native-library의 메인테이너인 Callstack과의 협력을 강화해 라이브러리 템플릿을 개선하고 React Native 프로젝트와의 통합을 위한 모든 필수 모범 사례를 준수하도록 했다. 이제 create-react-native-library의 최신 버전은 0.71 프로젝트와 완벽히 호환되며, 이전 버전과의 호환성도 유지한다.

결론​

전 세계 개발자의 업무 흐름에 방해가 된 점에 대해 진심으로 사과드린다. 앞서 언급했듯이, 우리는 이미 기반을 강화하기 위한 조치를 시작했으며, 더 많은 작업이 예정되어 있다.

이번 사건에 대한 통찰을 공유함으로써 여러분이 상황을 더 잘 이해하고, 우리의 경험을 활용해 각자의 도구와 프로젝트에 더 나은 방식을 적용할 수 있기를 바란다.

마지막으로, 아티팩트 제거를 도와준 Sonatype, 그리고 가능한 한 빨리 이 문제를 해결하기 위해 끊임없이 노력한 커뮤니티와 릴리스 팀에게 다시 한 번 감사의 말씀을 전한다.