建立永久工作站

回報問題 查看來源 Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

持續性工作站可加快建構速度。如果建構作業中重複執行的動作啟動成本高昂,或可從跨動作快取獲益,您不妨實作自己的持續性工作站來執行這些動作。

Bazel 伺服器會使用 stdin/stdout 與工作站通訊,並支援使用通訊協定緩衝區或 JSON 字串。

工作人員實作項目包含兩個部分:

製作工作站

持續性工作站須符合幾項規定:

  • 它會讀取 stdin 中的 WorkRequests
  • 它會將 WorkResponses (且僅限 WorkResponse) 寫入 stdout
  • 並接受 --persistent_worker 旗標。封裝函式必須辨識 --persistent_worker 命令列標記,且只有在傳遞該標記時,才會讓自身保持常駐狀態,否則必須執行一次性編譯並結束。

如果您的程式符合這些規定,即可做為持續性工作人員使用!

工作要求

WorkRequest 包含工作站的引數清單、代表工作站可存取輸入內容的路徑摘要配對清單 (這項資訊不會強制執行,但可用於快取),以及要求 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_verbose 標記傳遞至 Bazel 會將 verbosity 欄位設為 10,但您可以手動使用較小或較大的值,取得不同數量的輸出內容。

選用的 sandbox_dir 欄位僅供支援多工沙箱的 Worker 使用。

工作回覆

WorkResponse 包含要求 ID、零或非零的結束代碼,以及說明處理或執行要求時發生任何錯誤的輸出訊息。工作人員應擷取所呼叫任何工具的 stdoutstderr,並透過 WorkResponse 回報。將其寫入工作站程序的 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。單工要求會依序傳送,舉例來說,伺服器收到回應後才會傳送下一個要求 (取消要求除外,詳情請參閱下文)。

注意事項

  • 每個通訊協定緩衝區前面都會加上長度,格式為 varint (請參閱 MessageLite.writeDelimitedTo())。
  • JSON 要求和回應不會以大小指標開頭。
  • JSON 要求與 protobuf 採用相同的結構,但使用標準 JSON,且所有欄位名稱都採用駝峰式大小寫。
  • 為維持與 protobuf 相同的向後和向前相容性屬性,JSON 工作人員必須容許這些訊息中的不明欄位,並使用 protobuf 預設值處理遺漏的值。
  • Bazel 會將要求儲存為 protobuf,並使用 protobuf 的 JSON 格式將其轉換為 JSON

取消

工作者可以選擇允許在工作完成前取消工作要求。 這在搭配動態執行時特別實用,因為本機執行可能會定期遭到速度較快的遠端執行作業中斷。如要允許取消,請在 execution-requirements 欄位中新增 supports-worker-cancellation: 1 (如下所示),並設定 --experimental_worker_cancellation 旗標。

取消要求WorkRequest,且 cancel 欄位已設定 (同樣地,取消回應WorkResponse,且 was_cancelled 欄位已設定)。取消要求或取消回應中唯一必須有的其他欄位是 request_id,用來指出要取消哪個要求。單工工作站的request_id欄位為 0,多工工作站則為先前傳送的WorkRequest非 0 request_id。伺服器可能會針對工作人員已回應的要求傳送取消要求,在這種情況下,必須忽略取消要求。

每個非取消 WorkRequest 訊息都必須回覆一次,無論是否已取消。伺服器傳送取消要求後,工作站可能會傳回 WorkResponse,並將 request_id 設為 true,was_cancelled 欄位也設為 true。您也可以傳送一般 WorkResponse,但系統會忽略 outputexit_code 欄位。

WorkRequest 傳送回應後,工作站不得再處理工作目錄中的檔案。伺服器可自由清除檔案,包括暫存檔案。

建立使用 worker 的規則

您也需要建立規則,產生工作站要執行的動作。建立使用 Worker 的 Starlark 規則,與建立任何其他規則的過程相同。

此外,規則必須包含對工作人員本身的參照,且規則產生的動作須符合特定條件。

參照工作站

使用工作者的規則必須包含參照工作者本身的欄位,因此您需要建立 \*\_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" 表示應建構工作站,在執行平台而非目標平台上執行 (也就是說,工作站是在建構期間做為工具使用)。

工作動作規定

使用工作站的規則會建立工作站要執行的動作。這些動作有幾項規定。

  • 「arguments」欄位。這會採用字串清單,除了最後一個字串以外,其餘都是啟動時傳遞至工作站的引數。「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」屬性,除了代表輸入內容的「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 永續性工作站的多語言實作。您可以在 GitHub 上找到更多範例