本节涵盖了 Gradle 构建缓存的不同用例,从仅用于本地开发到在大型团队中缓存任务输出。

使用本地缓存加速开发者构建

即使只由一个开发者使用,构建缓存也非常有用。Gradle 的增量构建功能有助于避免重复工作,但一旦重新执行任务,之前的结果就会被遗忘。当你来回切换分支时,本地结果会被反复重建,即使你构建的东西之前已经构建过。构建缓存会记住先前的构建结果,并在本地已经构建过的情况下大大减少重建的需要。这也适用于重建不同的提交,例如运行 git bisect 时。

当项目有多个变体时(例如 Android 项目),本地缓存也非常有用。每个变体都关联着一些任务,其中一些任务变体维度虽然名称不同,但最终可能产生相同的输出。启用本地缓存后,在适用情况下,任务变体之间会自动发生复用。

在 CI 构建之间共享结果

构建缓存不仅仅能回溯时间:它还能弥合计算机之间的物理距离,允许在一台机器上生成的结果被另一台机器复用。在团队中引入构建缓存时,典型的第一步是仅为持续集成 (CI) 构建启用它。使用共享的 HTTP 构建缓存后端(例如由 Develocity 提供的后端)可以显著减少 CI Agent 的工作量。这意味着开发者能更快地获得反馈,并且节省 CI 资源的开销。更快的构建也意味着每次构建包含的提交更少,从而使调试问题更有效率。

在 CI 上开始使用构建缓存是一个很好的第一步,因为 CI Agent 的环境通常比开发者机器更稳定和可预测。这有助于识别构建中可能影响缓存性的任何潜在问题。

如果您需要对交付给客户的 artifacts 进行审计,则可能需要为某些构建禁用构建缓存。Develocity 可以帮助您在所有构建中使用构建缓存的同时满足这些要求。通过构建扫描,您可以轻松查明哪个构建通过构建缓存生成了 artifact。

from cache origin

通过复用 CI 结果加速开发者构建

当多个开发者处理同一个项目时,他们不仅需要构建自己的更改:每当从版本控制中拉取时,他们最终还需要构建彼此的更改。当开发者处理与拉取更改无关的内容时,他们可以安全地复用已在 CI 上生成的结果。例如,假设您正在开发模块 "A",并且拉取了模块 "B" 的一些更改(模块 "B" 不依赖于您的模块)。如果这些更改已在 CI 中构建,您可以从缓存中下载模块 "B" 的任务输出,而不是在本地生成。一个典型的用例是开发者开始一天的工作时,从版本控制中拉取所有更改,然后运行他们的第一次构建。

更改也不必完全独立;我们将在关于不同形式的归一化一节中,探讨涉及依赖项时复用结果的策略。

将远程结果与本地缓存结合使用

您可以结合使用本地缓存和远程缓存来产生复合效果。从填充了 CI 结果的远程缓存加载结果有助于避免由于其他开发者的更改而需要完成的工作,而本地缓存可以加快切换分支和执行 git bisect 的速度。在 CI 机器上,本地缓存可以作为远程缓存的镜像,显著减少网络使用。

在开发者之间共享结果

允许开发者将结果上传到共享缓存是可行的,但不推荐。开发者可以在任务执行期间更改任务输入或输出。他们可能会无意中这样做而没有注意到,例如在构建运行时在 IDE 中进行更改。目前,Gradle 没有很好的方法来防御这些更改,并且一旦任务完成,就会简单地缓存输出目录中的内容。这可能会导致损坏的结果被上传到共享缓存。当 Gradle 增加了必要的 safeguards 来防止任务输入和输出被无意修改时,此建议可能会改变。

如果您想共享增量构建(即非干净构建)的任务输出,则必须确保所有可缓存任务都已正确配置和实现,以处理过时的输出。例如,有些 annotation processors 不会清除相应 classes/resources 目录中的过时文件。缓存是解决这些问题的一个很好的“强制函数”,这也会使您的增量构建更加可靠。同时,在您确信增量构建行为完美无缺之前,请只使用干净构建将内容上传到缓存。