跳到主要内容

React Native 0.71-RC0 Android 故障事后分析

·阅读时长 8 分钟
Nicola Corti
Nicola Corti
Meta 软件工程师
Lorenzo Sciandra
Lorenzo Sciandra
微软高级软件工程师

鉴于 0.71 版本现已发布,我们希望分享关于此次事件的一些关键信息,该事件导致所有 React Native 版本的 Android 构建失败,发生于 2022 年 11 月 4 日发布首个 0.71 React Native 及 Expo Android 构建版本候选版本之时。

协助处理此事件的贡献者们最近参加了一次事后分析会议,详细讨论了事件的发生经过、我们从中汲取的教训,以及未来将采取哪些措施以避免类似故障再次发生。

事件经过

2022 年 11 月 4 日,我们在多个公共仓库发布了 React Native 0.71.0-rc0 版本,这是 0.71 版本的首个候选版本。

此候选版本中的一个重要变更,通过将构建产物发布到 Maven Central 而非从源代码构建,从而缩短了构建时间。有关具体实现方式的更多细节可在 RFC#508相关讨论中找到。

不幸的是,由于我们从模板脚手架新项目的方式,这导致了所有使用旧版 React Native 的 Android 用户构建失败,因为他们会开始下载 0.71.0-rc0 版本的新构建产物,而不是他们项目中所使用的版本(如 0.68.0)。

原因分析

React Native 模板提供了一个 `build.gradle` 文件用于构建 Android 应用。该文件包含对 React Native Android 库的如下依赖:`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 Issue 上找到。

如何缓解与解决

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 issue 上找到解决方案。

我们花了 48 小时才意识到此问题影响范围更广,且不能指望所有用户都能在 GitHub issue 上找到解决方案。我们需要优先采取更复杂的积极缓解措施,以自动修复用户项目。

我们将重新审视我们的流程,确定何时应依赖开发者手动应用的解决方案,以及何时可部署自动修复。我们还将研究如何更好地实时掌握我们生态系统的健康状况。

发布支持策略

rn-versions 工具所示,为了覆盖事件发生时 90% 以上的 React Native 开发者基础,我们不得不发布补丁,一直追溯到 0.63 版本。

我们认为这归因于 React Native 升级体验,其在历史上一直充满摩擦。我们目前正在研究改进升级体验的方法,使其更流畅、更快速,以缓解生态系统的碎片化问题。

发布新版 React Native 绝不应影响使用旧版的用户,我们对给您的工作流程造成的干扰深表歉意。

同样,我们也想强调,保持您的依赖项和 React Native 版本最新,以受益于我们引入的改进和保障措施的重要性。此次事件发生时,官方发布支持策略正在制定中,尚未对外公布或实施。

未来,我们将通过我们的沟通渠道公布支持策略,并考虑在 npm 上弃用旧版 React Native

改进第三方库的测试和最佳实践

此次事件突显了改进发布测试以及为第三方库提供更好指导的重要性。

在测试方面,发布直到 0.63.x 版本的补丁被证明具有挑战性,原因是我们目前针对稳定版本所具备的自动化和测试不足。我们认识到发布和测试基础设施的重要性,未来将对此进行进一步投入。

具体而言,我们现在鼓励并支持第三方库测试作为 React Native 发布过程的一部分。我们还在核心贡献者 Discord 服务器中增加了新的频道和角色。

在此之上,我们与 create-react-native-library 的维护者 Callstack 展开了更紧密的合作,旨在改进库模板,确保其遵循所有必要的最佳实践,以便与 React Native 项目集成。新版 `create-react-native-library` 现在完全兼容 0.71 项目,同时仍提供向后兼容性。

结论

我们对此次事件给全球开发者工作流程造成的干扰深表歉意。如上所述,我们已经开始采取行动来巩固我们的基础——未来还有更多工作要做。

我们希望分享这些见解能帮助大家更好地理解此次事件,并且能够借鉴我们的经验,在您自己的工具和项目中应用更好的实践。

最后,我们再次感谢 Sonatype 帮助我们移除了构建产物,感谢我们的社区,以及不知疲倦地尽快解决此问题的发布团队。