React Native 0.71-RC0 安卓故障事后分析
现在 0.71 版本已经发布,我们想分享一些关于 2022 年 11 月 4 日发布首个 0.71 候选版本时,导致所有 React Native 版本安卓构建失败的关键事件信息。
帮助处理此次事件的贡献者们近日参加了一个事后分析会议,详细讨论了事件的经过、我们从中学到了什么,以及未来将采取哪些措施来避免类似的故障。
事件经过
2022 年 11 月 4 日,我们发布了 React Native 版本 0.71.0-rc0,这是 0.71 的首个候选版本,发布到了多个公共仓库。
该版本候选发布了一个关键变更,通过将构建产物发布到 Maven Central,而不是从源码构建,从而提升了构建速度。关于这一做法的更多细节可以参见 RFC#508 以及相关讨论。
不幸的是,由于我们从模板搭建新项目的方式,导致旧版本安卓用户构建失败,因为构建时开始下载 0.71.0-rc0 版本的新工件,而不是项目中使用的版本(例如 0.68.0)。
事件原因
React Native 模板提供了一个 build.gradle 文件用于构建安卓应用。该文件包含对 React Native 安卓库的依赖:
implementation("com.facebook.react:react-native:+")。
这里的 + 部分是一个 Gradle 动态版本,它指示 Gradle 选取可用的最高版本。使用动态版本被认为是不良实践,因为它会导致构建结果难以复现。
我们意识到动态版本可能带来的问题,因此在 0.71 版本中清理了新的应用模板,移除了所有 + 依赖。然而,旧版本的 React Native 用户依然在使用 + 版本。
这导致 0.71.0-rc0 之前的 React Native 版本构建时,会在所有仓库查询最高可用的 React Native 版本。由于新推送到 Maven Central 的 0.71.0-rc0 是最高版本,使用早期版本的构建开始下载并使用了 0.71.0-rc0 的工件。本地构建版本(如 0.68.0)与 Maven Central 拿到的工件版本不匹配,导致构建失败。
此事件的更多技术细节可见于该 GitHub 问题。
我们如何缓解和解决
2022 年 11 月 4 日问题确认后,社区迅速发现并分享了一个手动的临时解决方法,固定 React Native 版本以纠正错误。
随后,在 11 月 5 日和 6 日的周末,发布团队为所有旧版本直至 0.63 进行了补丁发布,自动应用修复,使用户可升级到修复后的版本。
同时,我们联系了 Sonatype,请求移除相关有问题的工件。
该问题于 11 月 8 日彻底解决,当时相关工件从 Maven Central 被完全移除。
事件时间线
本节为事件简要时间线,所有时间均为 GMT/UTC +0
- 11 月 4 日 - 17:06:发布 0.71-RC0。
- 11 月 4 日 - 18:20:首次构建问题报告。
- 11 月 4 日 - 19:45:社区定位问题。
- 11 月 4 日 - 21:39:共享解决方案,Expo向所有用户部署修复。
- 11 月 5 日 - 03:04:新问题单开启,通报状态及解决方案。
- 11 月 6 日 - 16:11:给 Sonatype 开启移除工件请求。
- 11 月 6 日 - 16:40:@reactnative 发布首条推特,附带问题链接与确认。
- 11 月 6 日 - 19:05:决定为 React Native 版本回补至 0.63。
- 11 月 7 日 - 00:47:发布最后一个补丁版本:0.63.5。
- 11 月 8 日 - 20:04:Maven Central 上的工件被完全移除。
- 11 月 10 日 - 11:51:关于本事件的问题关闭。
学到的教训
虽然触发该事件的条件在 React Native 0.12.0 就存在,我们希望确保未来开发与发布 React Native 的基础更加稳固。以下是我们总结的经验教训和行动方案,用以改进流程和基础设施,以便未来能更快速且更强有力地响应类似事件。
事件响应策略
此次事件暴露了我们在应对开源 React Native 相关问题时事件响应策略的不足。
社区在不到 2 小时内迅速找到临时解决方案。由于缺乏对问题影响范围的清晰了解,且修复旧版本较为复杂,我们只能依赖受影响用户在 GitHub 问题中发现解决方法。
我们花了 48 小时才意识到问题影响范围远大,且不能依赖所有用户自行发现 GitHub 上的问题。必须优先考虑更加复杂的主动缓解措施,自动修复用户项目。
未来,我们将重新审视哪些情况可依赖开发者自行采取解决方案,哪些需要我们自动部署修复。同时,我们也会探索更好的手段实时监控生态健康状况。
发布支持策略
如在 rn-versions 工具中可见,这次为覆盖当时超过 90% 的 React Native 开发者用户,我们不得不为最低至 0.63 版本发布补丁。
我们认为这主要是由于 React Native 升级体验历来存在诸多摩擦造成的。我们正着手改进升级流程,期望未来升级能更加平滑快速,降低生态割裂的情况。
新版本 React Native 发布时绝不应该影响旧版本用户,针对工作流程的中断,我们深感抱歉。
同时,我们也希望强调,保持依赖和 React Native 的版本最新非常重要,以享受到改进和我们引入的安全措施。本事件发生时官方的发布支持政策仍在制定,尚未公布或强制执行。
未来,我们会通过沟通渠道传达支持政策,并考虑在 npm 上废弃旧版本 React Native。
改进测试及对第三方库的最佳实践指导
此次事件凸显了加强发布测试和为第三方库提供更好指导的重要性。
测试方面,向 0.63.x 版本回补补丁困难重重,原因在于我们现有稳定发布缺乏充足的自动化测试基础设施。我们认识到发布和测试基础设施的重要性,未来将加大投入。
具体而言,我们现在鼓励并支持第三方库在React Native 发布流程中进行测试。同时,也在核心贡献者 Discord 服务器增加了新的渠道和角色支持。
此外,我们开始与 Callstack(create-react-native-library的维护者)展开更紧密合作,改进库模板,确保符合 React Native 项目集成的最佳实践。更新后的 create-react-native-library 版本与 0.71 版本完全兼容且依旧支持向后兼容。
结论
我们对此次事件对全球开发者工作流造成的干扰深表歉意。如前所述,我们已经开始采取措施强化基础——但仍有许多工作要做。
我们希望通过分享这些洞见,帮助大家更好地理解本次事件,并能借鉴我们的经验,在自己的工具和项目中实施更好的实践。
最后,我们再次感谢 Sonatype 协助我们移除有问题工件,感谢社区的贡献,以及发布团队不懈努力,争取尽快解决此事件。

