缓存任务
本页介绍缓存任务的细节。有关一般说明,请参阅缓存。
自动缓存
val someKey = taskKey[String]("something")
someKey := name.value + version.value + "!"
在 sbt 2.x 中,任务结果将根据 name 和 version 两个设置自动缓存。首次运行任务时将在现场执行,第二次起将使用磁盘缓存:
sbt:demo> show someKey
[info] demo0.1.0-SNAPSHOT!
[success] elapsed time: 0 s, cache 0%, 1 onsite task
sbt:demo> show someKey
[info] demo0.1.0-SNAPSHOT!
[success] elapsed time: 0 s, cache 100%, 1 disk cache hit
缓存与序列化同样困难
要参与自动缓存,输入键(如 name 和 version)必须为 sjsonnew.HashWriter typeclass 提供 given 实例,返回类型必须为 sjsonnew.JsonFormat 提供 given 实例。
[error] -- Error: /Users/xxx/caching/project/FooPlugin.scala:17:4 -
[error] 17 | foo := {
[error] | ^
[error] |given evidence sjsonnew.JsonFormat[sbt.HashedVirtualFileRef] is not found; opt out of caching by annotating the key with @transient, or as foo := Def.uncached(...), or provide a given value
[error] |
[error] 18 | val b = baseDirectory.value
部分内置类型(如 HashedVirtualFileRef)的编解码器可通过 CacheImplicits.given 提供:
import CacheImplicits.given
....
override lazy val projectSettings: Seq[Setting[?]] = Seq(
foo := {
val b = baseDirectory.value
val conv = fileConverter.value
conv.toVirtualFile((b / "build.sbt").toPath)
},
bar := foo.value,
)
Contraband 可用于生成 sjson-new 编解码器。
效果跟踪
文件创建的效果
要缓存文件创建的效果(而不仅是返回文件名),需使用 Def.declareOutput(vf) 跟踪文件创建的效果。
someKey := {
val conv = fileConverter.value
val out: java.nio.file.Path = createFile(...)
val vf: xsbti.VirtualFile = conv.toVirtualFile(out)
Def.declareOutput(vf)
vf: xsbti.HashedVirtualFileRef
}
系统属性的影响
在缓存任务中捕获系统属性或环境变量会破坏缓存稳定性。考虑以下缓存任务:
lazy val someInt = taskKey[Int]("")
// BAD
someInt := {
sys.props("release").toInt + 1
}
首先假设我们使用 -Drelease=0 运行:
$ sbt --server -Drelease=0
....
sbt:caching> show someInt
[info] 1
[success] elapsed time: 0 s, cache 0%, 1 onsite task
然而,即使我们使用 -Drelease=1 运行,数值也不会改变:
$ sbt --server -Drelease=1
....
sbt:caching> show someInt
[info] 1
[success] elapsed time: 0 s, cache 100%, 1 disk cache hit
这是因为在使用缓存键时,someInt 只考察任务定义的形态以及输入设置与任务。要正确缓存 someInt,请将系统属性包装为设置,如下所示:
lazy val someInt = taskKey[Int]("")
lazy val releaseVer = settingKey[Int]("")
releaseVer := sys.props("release").toInt
someInt := releaseVer.value + 1
这将在每次加载构建时重新求值系统属性:
$ sbt --server -Drelease=1
sbt:caching> show someInt
[info] 2
[success] elapsed time: 0 s, cache 0%, 1 onsite tas
选择退出缓存
按任务键退出
若您希望某些任务键退出缓存,可按以下方式设置缓存级别:
@transient
val someKey = taskKey[String]("something")
或
@cacheLevel(include = Array.empty)
val someKey = taskKey[String]("something")
按任务退出
要单独退出缓存,请按以下方式使用 Def.uncached(...):
val someKey = taskKey[String]("something")
someKey := Def.uncached {
name.value + somethingUncachable.value + "!"
}
构建级退出
要选择退出默认的自定义任务缓存,请在 project/plugins.sbt 中添加以下内容:
Compile / scalacOptions += "-Xmacro-settings:sbt:no-default-task-cache"
远程缓存
sbt 2.x 实现了与 Bazel 兼容的 gRPC 接口,可与多种开源和商业后端配合使用。详见 远程缓存设置。