永久性工作器可让您的构建更快。如果 您的 build 中存在具有较高启动成本或 从交叉操作缓存中受益,您可能需要自行实现 来执行这些操作。
Bazel 服务器使用 stdin
/stdout
与工作器通信。它支持使用协议缓冲区或 JSON 字符串。
工作器实现分为两个部分:
使 worker
持久性工作器需要满足以下几项要求:
- 上面写着:
WorkRequests
从其
stdin
开始。 - 它会将 WorkResponse(仅限
WorkResponse
)写入其stdout
。 - 它接受
--persistent_worker
标志。封装容器必须识别--persistent_worker
命令行 flag,并且仅在满足以下条件时才会使自身持久保留: 否则必须进行单样本编译并退出。
如果您的程序遵守这些要求,则可将其用作 员工!
工作请求
WorkRequest
包含工作器的参数列表、表示工作器可以访问的输入的路径摘要对列表(系统不会强制执行此操作,但您可以使用此信息进行缓存),以及请求 ID(对于单工单工作器,此 ID 为 0)。
注意:虽然协议缓冲区规范使用“蛇形命名法”(request_id
),但 JSON 协议使用“驼峰命名法”(requestId
)。本文档中的 JSON 示例使用驼峰命名法,但在讨论字段时,无论协议如何,都使用蛇形命名法。
{
"arguments" : ["--some_argument"],
"inputs" : [
{ "path": "/path/to/my/file/1", "digest": "fdk3e2ml23d"},
{ "path": "/path/to/my/file/2", "digest": "1fwqd4qdd" }
],
"requestId" : 12
}
可选的 verbosity
字段可用于请求额外的调试输出
。输出什么以及如何输出完全由 worker 决定。较高
值表示输出更详细。将 --worker_verbose
标志传递给 Bazel 会将 verbosity
字段设置为 10,但您可以根据不同的输出量手动使用较小或较大的值。
可选的 sandbox_dir
字段仅供支持多重沙盒的 worker 使用。
工作响应
WorkResponse
包含请求 ID、零或非零退出代码,以及用于描述处理或执行请求时遇到的任何错误的输出字符串。output
字段包含简短说明;完整日志
写入 worker 的 stderr
。由于 worker 只能将 WorkResponses
写入 stdout
,因此 worker 通常会将其使用的任何工具的 stdout
重定向到 stderr
。
{
"exitCode" : 1,
"output" : "Action failed with the following message:\nCould not find input
file \"/path/to/my/file/1\"",
"requestId" : 12
}
根据 protobuf 的标准,所有字段都是可选的。不过,Bazel 要求 WorkRequest
和相应的 WorkResponse
具有相同的请求 ID,因此如果请求 ID 不为零,则必须指定请求 ID。这是一个有效的
WorkResponse
。
{
"requestId" : 12,
}
request_id
为 0 表示“单工”请求,用于
不能与其他请求并行处理。服务器可保证
给定工作器接收只有 request_id
0 或只有 0 的请求
request_id
大于零。单播请求是串行发送的,例如,服务器在收到响应之前不会发送其他请求(取消请求除外,详见下文)。
备注
- 每个协议缓冲区均以
varint
格式的长度开头(请参阅MessageLite.writeDelimitedTo()
。 - JSON 请求和响应的前面没有大小指示符。
- JSON 请求采用与 protobuf 相同的结构,但使用标准 JSON 并对所有字段名称使用驼峰式命名法。
- 为了保持与 protobuf 相同的向后和向前兼容性属性,JSON 工作器必须容忍这些消息中存在未知字段,并针对缺失的值使用 protobuf 默认值。
- Bazel 将请求存储为 protobuf,并使用 protobuf 的 JSON 格式
取消
工人可以选择允许在工作请求完成之前取消该请求。这特别适用于动态执行,因为本地
较快的远程执行则经常会中断执行。要允许
取消,请将 supports-worker-cancellation: 1
添加到
execution-requirements
字段(见下文),并将
--experimental_worker_cancellation
标志。
取消请求是设置了 cancel
字段的 WorkRequest
(同样,取消响应是设置了 was_cancelled
字段的 WorkResponse
)。取消请求或取消响应中必须包含的唯一其他字段是 request_id
,用于指明要取消哪个请求。request_id
对于单工工作器,字段将为 0;对于之前的作业,request_id
为非 0
为多路复用工作器发送了 WorkRequest
。服务器可能会针对 worker 已响应的请求发送取消请求,在这种情况下,必须忽略取消请求。
无论如何,对于每条非取消WorkRequest
消息,您都必须只回答一次,
而不是被取消了服务器发送取消请求后,工作器可能会响应 WorkResponse
,并将 request_id
设置为 true 并将 was_cancelled
字段设置为 true。您也可以发送常规的 WorkResponse
,但系统会忽略 output
和 exit_code
字段。
一旦发送针对 WorkRequest
的响应,Worker 就不得轻触
文件放在其工作目录中。服务器可以随意清理文件
包括临时文件。
创建使用 worker 的规则
您还需要创建规则,生成由 worker。创建使用 worker 的 Starlark 规则与创建任何其他规则一样。
此外,该规则需要包含对 worker 本身的引用,并且对其生成的操作有一些要求。
引用 worker
使用该 worker 的规则需要包含一个引用 worker 本身的字段,因此您需要创建 \*\_binary
规则的实例来定义 worker。如果您的工作器名为 MyWorker.Java
,则关联的规则可能是:
java_binary(
name = "worker",
srcs = ["MyWorker.Java"],
)
这会创建“工作器”标签,表示工作器二进制文件。然后,您将定义一项使用该 worker 的规则。此规则应定义一个 是指工作器二进制文件。
如果您构建的工作器二进制文件位于名为“work”的软件包中,该软件包位于顶部 构建级别,则可能是属性定义:
"worker": attr.label(
default = Label("//work:worker"),
executable = True,
cfg = "exec",
)
cfg = "exec"
表示应将 worker 构建为在您的
而不是在目标平台上运行(也就是说,使用 worker
用作工具)。
工作操作要求
使用工作器的规则会创建供工作器执行的操作。这些操作有一些要求。
"arguments" 字段。该函数接受一个字符串列表,除最后一个 它们是在启动时传递给 worker 的参数。“arguments”列表中的最后一个元素是
flag-file
(带有 @ 前缀)参数。工作器会按 WorkRequest 读取指定标志文件中的参数。您的规则可以将工作器的非启动参数写入此标志文件。"execution-requirements" 字段,接受包含
"supports-workers" : "1"
和/或"supports-multiplex-workers" : "1"
的字典。发送给工作器的所有操作都必须包含“arguments”和“execution-requirements”字段。此外,应由 JSON 工作器需要将
"requires-worker-protocol" : "json"
包含在 执行要求字段。"requires-worker-protocol" : "proto"
也是 有效的执行要求,但 proto 工作器不需要, 因为它们是默认设置您还可以在执行要求中设置
worker-key-mnemonic
。如果您要针对多种操作类型重复使用可执行文件,并且希望通过此 worker 区分操作,这可能会很有用。操作过程中生成的临时文件应保存到 worker 的目录。这会启用沙盒功能。
假设规则定义包含“worker”属性,除了
更改为“srcs”属性,即“output”属性
“args”属性,用于表示 worker
boot args 时,对 ctx.actions.run
的调用可能是:
ctx.actions.run(
inputs=ctx.files.srcs,
outputs=[ctx.outputs.output],
executable=ctx.executable.worker,
mnemonic="someMnemonic",
execution_requirements={
"supports-workers" : "1",
"requires-worker-protocol" : "json"},
arguments=ctx.attr.args + ["@flagfile"]
)
如需查看其他示例,请参阅 实现永久性工作器。
示例
除了在集成测试中使用的示例 JSON 工作器之外,Bazel 代码库还使用 Java 编译器工作器。
您可以使用 基架 通过传入正确的回调将任何基于 Java 的工具添加到 Worker 中。
有关使用工作器的规则示例,请查看 Bazel 的 工作器集成测试。
外部贡献者以多种语言协助员工开展工作;去 看看 Bazel 永久性工作器的 Polyglot 实现。 您可以在 GitHub 上找到更多示例!