ผู้ปฏิบัติงานแบบถาวรช่วยให้การบิลด์เร็วขึ้นได้ หากคุณมีการดำเนินการซ้ำๆ ในการบิลด์ซึ่งมีค่าใช้จ่ายในการเริ่มต้นสูงหรือได้รับประโยชน์จากการแคชข้ามการดำเนินการ คุณอาจต้องการใช้ผู้ปฏิบัติงานแบบถาวรของคุณเองเพื่อดำเนินการเหล่านี้
เซิร์ฟเวอร์ Bazel สื่อสารกับผู้ปฏิบัติงานโดยใช้ stdin/stdout และรองรับการใช้บัฟเฟอร์โปรโตคอลหรือสตริง JSON
การใช้งานของผู้ปฏิบัติงานมี 2 ส่วน ได้แก่
การสร้างผู้ปฏิบัติงาน
ผู้ปฏิบัติงานแบบถาวรต้องเป็นไปตามข้อกำหนดบางประการ ดังนี้
- อ่าน
WorkRequests
จาก
stdin - เขียน
WorkResponses
(และ
WorkResponseเท่านั้น) ลงในstdout - ยอมรับแฟล็ก
--persistent_workerแรปเปอร์ต้องจดจำแฟล็กบรรทัดคำสั่ง--persistent_workerและทำให้ตัวเองเป็นแบบถาวรก็ต่อเมื่อมีการส่งแฟล็กดังกล่าว ไม่เช่นนั้นจะต้องทำการคอมไพล์แบบครั้งเดียวและออก
หากโปรแกรมของคุณเป็นไปตามข้อกำหนดเหล่านี้ ก็สามารถใช้เป็นผู้ปฏิบัติงานแบบถาวรได้
คำขอทำงาน
WorkRequest มีรายการอาร์กิวเมนต์สำหรับผู้ปฏิบัติงาน รายการคู่เส้นทาง-ไดเจสต์ที่แสดงอินพุตที่ผู้ปฏิบัติงานเข้าถึงได้ (ระบบไม่ได้บังคับ แต่คุณใช้ข้อมูลนี้สำหรับการแคชได้) และรหัสคำขอ ซึ่งเป็น 0 สำหรับผู้ปฏิบัติงานแบบซิงเกิลเพล็กซ์
หมายเหตุ: แม้ว่าข้อกำหนดบัฟเฟอร์โปรโตคอลจะใช้ "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_verbose ไปยัง Bazel จะตั้งค่าฟิลด์ verbosity เป็น 10 แต่คุณสามารถใช้ค่าที่น้อยกว่าหรือมากกว่าด้วยตนเองสำหรับเอาต์พุตจำนวนต่างๆ ได้
ฟิลด์ sandbox_dir ที่ไม่บังคับใช้โดยผู้ปฏิบัติงานที่รองรับ
แซนด์บ็อกซ์แบบมัลติเพล็กซ์เท่านั้น
การตอบสนองต่อคำขอทำงาน
WorkResponse มีรหัสคำขอ รหัสออกเป็น 0 หรือไม่ใช่ 0 และข้อความเอาต์พุตที่อธิบายข้อผิดพลาดที่พบในการประมวลผลหรือการดำเนินการคำขอ ผู้ปฏิบัติงานควรบันทึก stdout และ stderr ของเครื่องมือที่เรียกใช้และรายงานผ่าน 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 ที่เกี่ยวข้องต้องมีรหัสคำขอเดียวกัน ดังนั้นคุณต้องระบุรหัสคำขอหากไม่ใช่ 0 นี่คือ WorkResponse ที่ถูกต้อง
{
"requestId" : 12,
}
request_id ที่เป็น 0 แสดงถึงคำขอ "ซิงเกิลเพล็กซ์" ซึ่งใช้เมื่อไม่สามารถประมวลผลคำขอนี้แบบขนานกับคำขออื่นๆ ได้ เซิร์ฟเวอร์รับประกันว่าผู้ปฏิบัติงานที่กำหนดจะได้รับคำขอที่มี request_id เป็น 0 เท่านั้น หรือมี request_id มากกว่า 0 เท่านั้น ระบบจะส่งคำขอซิงเกิลเพล็กซ์แบบอนุกรม เช่น เซิร์ฟเวอร์จะไม่ส่งคำขออื่นจนกว่าจะได้รับคำตอบ (ยกเว้นคำขอให้ยกเลิก ดูด้านล่าง)
หมายเหตุ
- บัฟเฟอร์โปรโตคอลแต่ละรายการจะมีขนาดนำหน้าใน
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 สำหรับผู้ปฏิบัติงานแบบซิงเกิลเพล็กซ์ หรือ request_id ที่ไม่ใช่ 0 ของ WorkRequest ที่ส่งก่อนหน้านี้สำหรับผู้ปฏิบัติงานแบบมัลติเพล็กซ์ เซิร์ฟเวอร์อาจส่งคำขอให้ยกเลิกสำหรับคำขอที่ผู้ปฏิบัติงานตอบกลับไปแล้ว ในกรณีนี้ต้องละเว้นคำขอให้ยกเลิก
ข้อความ WorkRequest ที่ไม่ใช่คำขอให้ยกเลิกแต่ละข้อความต้องได้รับคำตอบเพียงครั้งเดียว ไม่ว่าจะยกเลิกหรือไม่ก็ตาม เมื่อเซิร์ฟเวอร์ส่งคำขอให้ยกเลิกแล้ว ผู้ปฏิบัติงานอาจตอบกลับด้วย WorkResponse ที่ตั้งค่า request_id และตั้งค่าฟิลด์ was_cancelled เป็น "จริง" ระบบยังยอมรับการส่ง WorkResponse ปกติด้วย แต่จะละเว้นฟิลด์ output และ exit_code
เมื่อส่งการตอบสนองสำหรับ WorkRequest แล้ว ผู้ปฏิบัติงานต้องไม่แตะต้องไฟล์ในไดเรกทอรีการทำงาน เซิร์ฟเวอร์มีอิสระในการล้างไฟล์ รวมถึงไฟล์ชั่วคราว
การสร้างกฎที่ใช้ผู้ปฏิบัติงาน
คุณจะต้องสร้างกฎที่สร้างการดำเนินการให้ผู้ปฏิบัติงานดำเนินการด้วย การสร้างกฎ 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" ระบุว่าควรสร้างผู้ปฏิบัติงานให้ทำงานบน
แพลตฟอร์มการดำเนินการของคุณแทนที่จะเป็นแพลตฟอร์มเป้าหมาย (เช่น ใช้ผู้ปฏิบัติงานเป็นเครื่องมือระหว่างการบิลด์)
ข้อกำหนดการดำเนินการของผู้ปฏิบัติงาน
กฎที่ใช้ผู้ปฏิบัติงานจะสร้างการดำเนินการให้ผู้ปฏิบัติงานดำเนินการ การดำเนินการเหล่านี้มีข้อกำหนด 2 ข้อ
ฟิลด์ "arguments" ฟิลด์นี้ใช้รายการสตริง ซึ่งทั้งหมดแต่ไม่ใช่รายการสุดท้ายเป็นอาร์กิวเมนต์ที่ส่งไปยังผู้ปฏิบัติงานเมื่อเริ่มต้น องค์ประกอบสุดท้ายในรายการ "arguments" คืออาร์กิวเมนต์
flag-file(นำหน้าด้วย @) ผู้ปฏิบัติงานจะอ่านอาร์กิวเมนต์จากแฟล็กไฟล์ที่ระบุตาม WorkRequest แต่ละรายการ กฎของคุณสามารถเขียนอาร์กิวเมนต์ที่ไม่ใช่การเริ่มต้นสำหรับผู้ปฏิบัติงานลงในแฟล็กไฟล์นี้ได้ฟิลด์ "execution-requirements" ซึ่งใช้พจนานุกรมที่มี
"supports-workers" : "1","supports-multiplex-workers" : "1", หรือทั้ง 2 อย่างฟิลด์ "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"]
)
ดูอีกตัวอย่างได้ที่ การใช้งานผู้ปฏิบัติงานแบบถาวร
ตัวอย่าง
ฐานของโค้ด Bazel ใช้ ผู้ปฏิบัติงานคอมไพเลอร์ Java, นอกเหนือจาก ผู้ปฏิบัติงาน JSON ตัวอย่าง ที่ใช้ในการทดสอบการผสานรวม
คุณสามารถใช้ โครงสร้างพื้นฐาน เพื่อเปลี่ยนเครื่องมือที่ใช้ Java ให้เป็นผู้ปฏิบัติงานได้โดยการส่งการเรียกกลับที่ถูกต้อง
หากต้องการดูตัวอย่างกฎที่ใช้ผู้ปฏิบัติงาน โปรดดูการทดสอบการผสานรวมผู้ปฏิบัติงานของ Bazel
ผู้มีส่วนร่วมภายนอกได้ใช้งานผู้ปฏิบัติงานในภาษาต่างๆ มากมาย โปรดดูการใช้งานผู้ปฏิบัติงานแบบถาวรของ Bazel ในหลายภาษา ดูตัวอย่างเพิ่มเติมได้มากมายใน GitHub !