永久工作站可加快建構速度。如果您在建構作業中發現重複動作,且啟動成本高昂,或可透過跨動作快取受益,建議您實作自己的永久工作站來執行這些動作。
Bazel 伺服器使用 stdin
/stdout
與工作站通訊,該伺服器支援使用通訊協定緩衝區或 JSON 字串。
工作站實作包含兩個部分:
讓工作站成為工作站
永久性工作站需要滿足以下幾項需求:
- 該程式碼會從其
stdin
讀取 WorkRequests。 - 它會將 WorkResponses (且僅限
WorkResponse
) 寫入其stdout
。 - 它接受
--persistent_worker
旗標。包裝函式必須辨識--persistent_worker
指令列旗標,且只在傳遞旗標時使自身持續持久,否則必須執行一次性編譯並結束。
如果您的程式符合這些要求,即可做為持續工作站使用!
工作要求
WorkRequest
包含工作站引數清單、路徑摘要組合清單,代表工作站可以存取的輸入內容 (這並非強制規定,但您可以使用這項資訊進行快取),以及要求 ID (適用於單一複雜工作站)。
注意:雖然通訊協定緩衝區規格使用的是「蛇例」(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_verbose
標記傳送至 Bazel 會將 verbosity
欄位設為 10,但您可以手動將較小或更大的值用於不同的輸出量。
選擇性的 sandbox_dir
欄位僅供支援多工沙箱的工作站使用。
工作回應
WorkResponse
包含要求 ID、零或非零結束代碼,以及說明處理或執行要求時發生的任何錯誤輸出字串。output
欄位包含簡短說明;您可以將完整的記錄寫入工作站的 stderr
。由於 worker 只能將 WorkResponses
寫入 stdout
,因此工作站通常會將所用工具的 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。這是有效的 WorkResponse
。
{
"requestId" : 12,
}
request_id
為 0 表示「單一複雜」要求,在無法與其他要求並行處理時使用。伺服器可保證特定工作站收到的要求只有 request_id
0 或只有 request_id
大於零。單一複雜要求會以依序傳送,例如伺服器在收到回應之前不會傳送另一個要求 (取消要求除外,請參閱下方說明)。
Notes
- 每個通訊協定緩衝區前方都會加上
varint
格式的長度 (請參閱MessageLite.writeDelimitedTo()
)。 - JSON 要求和回應的前面不會加上大小指標。
- JSON 要求的結構與 protobuf 相同,但針對所有欄位名稱使用標準 JSON,並採用駝峰式大小寫。
- 為了保持與 protobuf 相同的回溯及向前相容性屬性,JSON 工作站必須容忍這些訊息中的不明欄位,並針對遺漏值使用 protobuf 預設值。
- Bazel 會將要求儲存為 protobufs,並使用 protobuf 的 JSON 格式將其轉換為 JSON。
取消
工作站可選擇允許在完成工作要求前取消工作要求。這對動態執行來說特別有用,因為在動態執行中,本機執行可以由更快的遠端執行而中斷。如要允許取消,請在 execution-requirements
欄位中加入 supports-worker-cancellation: 1
(請見下方說明),並設定 --experimental_worker_cancellation
標記。
取消要求是指已設定 cancel
欄位的 WorkRequest
(同樣地,取消回應是指具有 was_cancelled
欄位集的 WorkResponse
)。另一個必須在取消要求或取消回應中的欄位是 request_id
,表示要取消哪個要求。如果是單一複雜工作站,request_id
欄位會是 0,而如果是多 x 工作站,先前傳送 WorkRequest
的非 0 request_id
則會是非 0。伺服器可能會針對工作站已回應的要求傳送取消要求,在這種情況下,您必須忽略取消要求。
每則非取消的 WorkRequest
訊息無論是否取消,您都必須回覆一次。伺服器傳送取消要求後,工作站可能會回應 WorkResponse
,並設定 request_id
和 was_cancelled
欄位設為 true。系統也接受傳送一般的 WorkResponse
,但系統會忽略 output
和 exit_code
欄位。
向 WorkRequest
傳送回應之後,工作站不得輕觸工作目錄中的檔案。伺服器可以免費清理這些檔案,包括暫存檔案。
建立使用工作站的規則
您還需要建立規則,用來產生工作站要執行的動作。建立使用工作站的 Starlark 規則與建立任何其他規則一樣。
此外,規則必須包含 worker 本身的參照,而該規則所產生動作必須符合一些要求。
參照工作站
使用工作站的規則必須包含一個參照該工作站的欄位,因此您需要建立 \*\_binary
規則的執行個體來定義工作站。如果工作站稱為 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 執行的動作。這些動作有幾項要求。
"引數" 欄位。這會取得字串清單,但最後一個項目除外,也就是在啟動時傳遞至工作站的引數。「引數」清單中的最後一個元素是
flag-file
(@ 引號) 引數。工作站會根據個別工作要求,從指定的旗標檔案讀取引數。您的規則可以將工作站的非啟動引數寫入這個旗標檔案。"execution-requirements" 欄位,可使用包含
"supports-workers" : "1"
和/或"supports-multiplex-workers" : "1"
的字典。傳送至工作站的所有動作都需要「引數」和「執行要求」欄位。此外,需由 JSON 工作站所執行的動作必須在執行要求欄位中納入
"requires-worker-protocol" : "json"
。"requires-worker-protocol" : "proto"
也是有效的執行要求,但由於 proto 工作站是預設值,因此並非必要。您也可以在執行要求中設定
worker-key-mnemonic
。如果您要針對多個動作類型重複使用執行檔,且想要區分此 worker 的動作,這項功能可能會很有幫助。在動作過程中產生的暫存檔案應儲存在 worker 的目錄。即可啟用沙箱機制。
假設有一個規則定義含有「worker」屬性,除了代表輸入的「srcs」屬性、代表輸出的「output」屬性,以及代表工作站啟動引數的「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 型工具加入工作站。
如需使用工作站的規則範例,請查看 Bazel 的工作站整合測試。
外部貢獻者已透過各種語言實作工作站;請參考 Bazel 永久工作站的 Polyglot 實作。您可以前往 GitHub 查看更多範例!