Worker แบบถาวรช่วยให้คุณสร้างได้เร็วขึ้น หากคุณมีการดำเนินการซ้ำๆ ในบิลด์ที่มีต้นทุนเริ่มต้นสูงหรือจะได้รับประโยชน์จากการแคชข้ามการดำเนินการ คุณอาจต้องใช้ Worker แบบถาวรของคุณเองเพื่อดำเนินการเหล่านี้
เซิร์ฟเวอร์ Bazel สื่อสารกับ Worker โดยใช้ stdin/stdout ซึ่งรองรับการใช้บัฟเฟอร์โปรโตคอลหรือสตริง JSON
การใช้งาน Worker มี 2 ส่วน ดังนี้
การสร้างผู้ปฏิบัติงาน
Worker ที่ทำงานอย่างต่อเนื่องจะปฏิบัติตามข้อกำหนดต่อไปนี้
- โดยจะอ่าน
WorkRequests
จาก
stdin - โดยจะเขียน
WorkResponses
(และเฉพาะ
WorkResponses) ลงในstdout - โดยรับธง
--persistent_workerWrapper ต้องรู้จัก--persistent_workerแฟล็กบรรทัดคำสั่ง และทำให้ตัวเองคงอยู่เฉพาะในกรณีที่มีการส่งแฟล็ก ดังกล่าว ไม่เช่นนั้นจะต้องทำการคอมไพล์แบบครั้งเดียวแล้วออก
หากโปรแกรมของคุณเป็นไปตามข้อกำหนดเหล่านี้ ก็สามารถใช้เป็น Worker ที่ทำงานอย่างต่อเนื่องได้
คำของาน
WorkRequestประกอบด้วยรายการอาร์กิวเมนต์สำหรับ Worker, รายการคู่เส้นทาง-แฮชที่แสดงอินพุตที่ Worker เข้าถึงได้ (ระบบไม่ได้บังคับ แต่คุณใช้ข้อมูลนี้สำหรับการแคชได้) และรหัสคำขอ ซึ่งเป็น 0 สำหรับ Worker แบบ Singleplex
หมายเหตุ: แม้ว่าข้อกำหนดของบัฟเฟอร์โปรโตคอลจะใช้ "snake case" (request_id)
แต่โปรโตคอล JSON จะใช้ "camel case" (requestId) เอกสารนี้ใช้ camel case
ในตัวอย่าง JSON แต่ใช้ snake case เมื่อพูดถึงฟิลด์โดยไม่คำนึงถึง
โปรโตคอล
{
"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ฟิลด์ที่ไม่บังคับใช้โดยผู้ปฏิบัติงานที่รองรับแซนด์บ็อกซ์แบบมัลติเพล็กซ์เท่านั้น
การตอบกลับที่ทำงาน
WorkResponseมีรหัสคำขอ รหัสออกเป็น 0 หรือไม่ใช่ 0 และข้อความเอาต์พุตที่อธิบายข้อผิดพลาดที่พบในการประมวลผลหรือการดำเนินการคำขอ Worker ควรบันทึก stdout และ stderr ของเครื่องมือที่เรียกใช้ และรายงานผ่าน WorkResponse การเขียนไปยัง stdout ของ
กระบวนการของ Worker ไม่ปลอดภัยเนื่องจากจะรบกวนโปรโตคอลของ Worker
การเขียนไปยัง stderr ของกระบวนการ Worker นั้นปลอดภัย แต่ระบบจะรวบรวมผลลัพธ์ในไฟล์บันทึกต่อ Worker แทนที่จะระบุเป็นการดำเนินการแต่ละรายการ
{
"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 ที่เกี่ยวข้องต้องมีรหัสคำขอเดียวกัน
ดังนั้นจึงต้องระบุรหัสคำขอหากไม่ใช่ 0 นี่คือ
WorkResponse ที่ถูกต้อง
{
"requestId" : 12,
}
request_id ที่มีค่าเป็น 0 แสดงถึงคำขอ "Singleplex" ซึ่งใช้เมื่อคำขอนี้
ประมวลผลแบบขนานกับคำขออื่นๆ ไม่ได้ เซิร์ฟเวอร์รับประกันว่า
ผู้ปฏิบัติงานที่กำหนดจะได้รับคำขอที่มี request_id 0 เท่านั้นหรือมี
request_id มากกว่า 0 เท่านั้น คำขอแบบ Singleplex จะส่งเป็นชุด เช่น หากเซิร์ฟเวอร์ไม่ส่งคำขออื่นจนกว่าจะได้รับการตอบกลับ (ยกเว้นคำขอยกเลิก โปรดดูด้านล่าง)
หมายเหตุ
- แต่ละ Protocol Buffer จะมีคำนำหน้าเป็นความยาวในรูปแบบ
varint(ดูMessageLite.writeDelimitedTo() - คำขอและการตอบกลับ JSON จะไม่มีตัวบ่งชี้ขนาดนำหน้า
- คำขอ JSON จะคงโครงสร้างเดียวกับ Protobuf แต่ใช้ JSON มาตรฐาน และใช้รูปแบบ Camel Case สำหรับชื่อฟิลด์ทั้งหมด
- เพื่อให้คงคุณสมบัติความเข้ากันได้แบบย้อนกลับและไปข้างหน้าเช่นเดียวกับ Protobuf ผู้ปฏิบัติงาน JSON ต้องยอมรับฟิลด์ที่ไม่รู้จักในข้อความเหล่านี้ และใช้ค่าเริ่มต้นของ Protobuf สำหรับค่าที่ขาดหายไป
- Bazel จัดเก็บคำขอเป็น Protobuf และแปลงเป็น JSON โดยใช้รูปแบบ JSON ของ Protobuf
การยกเลิก
ผู้ปฏิบัติงานสามารถเลือกอนุญาตให้ยกเลิกคำของานก่อนที่จะเสร็จสิ้นได้
ซึ่งมีประโยชน์อย่างยิ่งในการเชื่อมต่อกับการดำเนินการแบบไดนามิก ซึ่งการดำเนินการในเครื่องอาจถูกขัดจังหวะเป็นประจำด้วยการดำเนินการจากระยะไกลที่เร็วกว่า หากต้องการอนุญาตให้ยกเลิก ให้เพิ่ม supports-worker-cancellation: 1 ลงในช่อง
execution-requirements (ดูด้านล่าง) และตั้งค่าแฟล็ก
--experimental_worker_cancellation
คำขอยกเลิกคือ WorkRequest ที่ตั้งค่าฟิลด์ cancel (และในทำนองเดียวกัน การตอบกลับการยกเลิกคือ WorkResponse ที่ตั้งค่าฟิลด์ was_cancelled) ฟิลด์อื่นๆ เพียงฟิลด์เดียวที่ต้องอยู่ในคำขอยกเลิกหรือการตอบกลับการยกเลิกคือ request_id ซึ่งระบุคำขอที่จะยกเลิก request_id
ฟิลด์จะเป็น 0 สำหรับ Worker แบบ Singleplex หรือ request_id ที่ไม่ใช่ 0 ของ WorkRequest ที่ส่งก่อนหน้านี้
สำหรับ Worker แบบ Multiplex เซิร์ฟเวอร์อาจส่งคำขอยกเลิก
สำหรับคำขอที่ Worker ตอบกลับไปแล้ว ในกรณีนี้
ต้องไม่สนใจคำขอยกเลิก
ข้อความWorkRequestที่ไม่ใช่การยกเลิกแต่ละข้อความต้องได้รับการตอบกลับเพียงครั้งเดียว ไม่ว่าจะมีการยกเลิกหรือไม่ก็ตาม
เมื่อเซิร์ฟเวอร์ส่งคำขอยกเลิกแล้ว Worker อาจ
ตอบกลับด้วย WorkResponse โดยตั้งค่า request_id และตั้งค่าฟิลด์ was_cancelled
เป็นจริง นอกจากนี้ยังยอมรับการส่ง WorkResponse ปกติด้วย แต่ระบบจะไม่สนใจฟิลด์
output และ exit_code
เมื่อส่งการตอบกลับสำหรับ WorkRequest แล้ว ผู้ปฏิบัติงานต้องไม่แตะต้อง
ไฟล์ในไดเรกทอรีการทำงาน เซิร์ฟเวอร์มีอิสระในการล้างไฟล์
รวมถึงไฟล์ชั่วคราว
สร้างกฎที่ใช้ Worker
นอกจากนี้ คุณยังต้องสร้างกฎที่สร้างการดำเนินการซึ่ง Worker จะต้องทำด้วย การสร้างกฎ Starlark ที่ใช้ Worker ก็เหมือนกับการสร้างกฎอื่นๆ
นอกจากนี้ กฎต้องมีการอ้างอิงถึงตัว Worker เอง และ การดำเนินการที่กฎสร้างขึ้นต้องเป็นไปตามข้อกำหนดบางอย่าง
การอ้างอิงถึงผู้ปฏิบัติงาน
กฎที่ใช้ Worker ต้องมีฟิลด์ที่อ้างอิงถึง Worker เอง ดังนั้นคุณจะต้องสร้างอินสแตนซ์ของกฎ \*\_binary เพื่อกำหนด Worker หาก Worker ชื่อ MyWorker.Java กฎที่เกี่ยวข้องอาจเป็นดังนี้
java_binary(
name = "worker",
srcs = ["MyWorker.Java"],
)
ซึ่งจะเป็นการสร้างป้ายกำกับ "worker" ที่อ้างอิงถึงไบนารีของ Worker จากนั้นคุณจะ กำหนดกฎที่ใช้ Worker กฎนี้ควรกำหนดแอตทริบิวต์ที่อ้างอิงไบนารีของ Worker
หากไบนารีของ Worker ที่คุณสร้างอยู่ในแพ็กเกจชื่อ "work" ซึ่งอยู่ที่ระดับบนสุดของการบิลด์ คำจำกัดความของแอตทริบิวต์อาจเป็นดังนี้
"worker": attr.label(
default = Label("//work:worker"),
executable = True,
cfg = "exec",
)
cfg = "exec" แสดงว่าควรสร้าง Worker ให้ทำงานบนแพลตฟอร์มการดำเนินการ
แทนที่จะเป็นบนแพลตฟอร์มเป้าหมาย (กล่าวคือ ใช้ Worker
เป็นเครื่องมือในระหว่างการสร้าง)
ข้อกำหนดในการดำเนินการกับงาน
กฎที่ใช้ Worker จะสร้างการดำเนินการให้ Worker ทำ การดำเนินการเหล่านี้มีข้อกำหนดบางประการ
ฟิลด์ "arguments" ซึ่งรับรายการสตริง โดยสตริงทั้งหมด ยกเว้นสตริงสุดท้าย จะเป็นอาร์กิวเมนต์ที่ส่งไปยัง Worker เมื่อเริ่มต้น องค์ประกอบสุดท้ายในรายการ "arguments" คืออาร์กิวเมนต์
flag-file(นำหน้าด้วย @) Worker จะอ่าน อาร์กิวเมนต์จากไฟล์แฟล็กที่ระบุตาม WorkRequest แต่ละรายการ กฎของคุณสามารถเขียนอาร์กิวเมนต์ที่ไม่ใช่การเริ่มต้นสำหรับ Worker ไปยัง Flagfile นี้ได้ฟิลด์ "execution-requirements" ซึ่งรับพจนานุกรมที่มี
"supports-workers" : "1","supports-multiplex-workers" : "1"หรือทั้งสองอย่างต้องระบุฟิลด์ "arguments" และ "execution-requirements" สำหรับการดำเนินการทั้งหมดที่ส่งไปยังผู้ปฏิบัติงาน นอกจากนี้ การดำเนินการที่ควรดำเนินการโดย Worker JSON ต้องมี
"requires-worker-protocol" : "json"ใน ช่องข้อกำหนดในการดำเนินการ"requires-worker-protocol" : "proto"ยังเป็นข้อกำหนดการดำเนินการที่ถูกต้องด้วย แม้ว่าจะไม่จำเป็นสำหรับผู้ปฏิบัติงาน Proto เนื่องจากเป็นค่าเริ่มต้นคุณยังตั้งค่า
worker-key-mnemonicในข้อกำหนดการดำเนินการได้ด้วย ซึ่งอาจมีประโยชน์หากคุณนำไฟล์ที่เรียกใช้งานได้กลับมาใช้ซ้ำสำหรับประเภทการดำเนินการหลายประเภท และต้องการแยกความแตกต่างของการดำเนินการตาม Worker นี้ควรบันทึกไฟล์ชั่วคราวที่สร้างขึ้นระหว่างการดำเนินการไว้ในไดเรกทอรีของ Worker ซึ่งจะช่วยให้ใช้แซนด์บ็อกซ์ได้
สมมติว่ามีการกำหนดกฎที่มีแอตทริบิวต์ "worker" ตามที่อธิบายไว้ข้างต้น นอกเหนือจากแอตทริบิวต์ "srcs" ที่แสดงถึงอินพุต แอตทริบิวต์ "output" ที่แสดงถึงเอาต์พุต และแอตทริบิวต์ "args" ที่แสดงถึงอาร์กิวเมนต์การเริ่มต้นของ Worker การเรียกใช้ 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"]
)
ดูอีกตัวอย่างได้ที่ การใช้งาน Worker แบบถาวร
ตัวอย่าง
โค้ดเบสของ Bazel ใช้โปรแกรมช่วยคอมไพเลอร์ Java นอกเหนือจากโปรแกรมช่วย JSON ตัวอย่าง ที่ใช้ในการทดสอบการผสานรวม
คุณสามารถใช้โครงสร้างพื้นฐาน เพื่อเปลี่ยนเครื่องมือที่ใช้ Java ให้เป็น Worker ได้โดยส่งการเรียกกลับที่ถูกต้อง
ดูตัวอย่างกฎที่ใช้ Worker ได้ที่การทดสอบการผสานรวม Worker ของ Bazel
ผู้ร่วมให้ข้อมูลภายนอกได้ติดตั้งใช้งาน Worker ในภาษาต่างๆ โปรดดูการติดตั้งใช้งาน Worker แบบถาวรของ Bazel ในหลายภาษา คุณดูตัวอย่างอื่นๆ อีกมากมายได้ใน GitHub