SoundCloud 的 JVMKit 库为数百个内部 Scala、Java、Clojure 和 JRuby 服务提供了共享的 JVM 模式——服务脚手架、数据库和 Kafka 集成、指标。随着采用范围扩大,平台团队失去了对哪些服务依赖 JVMKit API 的哪些部分的可见性,使得每次发布都成了一场赌博:一次例行更新可能悄无声息地破坏团队甚至不知道会受影响的服务。

由于 SoundCloud 的依赖关系在每个仓库的构建文件中显式声明(JVM 用 sbt,Android 用 Gradle,Web 用 npm),团队用 Zoekt(一个基于正则表达式的代码搜索引擎)为每个仓库建立了索引,每五分钟刷新一次。对构建文件进行简单查询,列出将 JVMKit 列为依赖项的文件,就能生成一个实时的反向依赖图——每个会受 JVMKit 变更影响的服务,都是自动生成的,而非手工跟踪。

有了这个图,团队构建了一条验证流水线:对于每个依赖服务,克隆仓库,在不做任何修改的情况下编译并测试它以建立基线,然后换入候选的 JVMKit 版本,应用针对已知破坏性 API 变更的任何脚本化修复,再次编译并测试。如果基线通过但候选版本失败,那么原因就是 JVMKit 的变更,而不是该服务中预先存在的故障。该检查每晚对全部依赖集运行,并在每个拉取请求上对一个更快的、列入允许列表的子集运行。

在发布库之前编译并测试每个调用方

它用一个自动化的、可证伪的检查取代了手动、易出错的流程(发布,然后等待团队抱怨),该检查在发布上线之前运行。

先运行未修改的基线,可以隔离出失败是来自 JVMKit 的变更,还是来自当天已经出故障的服务。

将验证拆分为每晚全量运行和快速的 PR 范围运行,既保持了反馈的快速性,又没有跳过全量覆盖。

反向依赖图是从代码生成的,而非手工维护,因此随着服务的增加或移除,它始终保持准确。

当一个内部库位于数百个服务之下时,不要靠运气发布——让依赖图可查询,并让 CI 先测试每个下游调用方。

JVMKit 继续为 SoundCloud 的数百个服务和数千个生产实例提供支持。有了验证流水线,平台团队报告称 JVMKit 的发布频率更高了,失败可以追溯到具体的步骤和具体的原因,而不是作为无法解释的故障在下游浮现。

从这里,追溯依据

参考来源

  1. Did I Break You? Reverse Dependency Verification SoundCloud Engineering · developers.soundcloud.com ·