การสร้างผู้ปฏิบัติงานถาวร

ผู้ปฏิบัติงานแบบถาวรจะช่วยให้บิลด์เร็วขึ้น หากคุณมีการดำเนินการซ้ำๆ ในบิลด์ที่มีต้นทุนเริ่มต้นสูงหรือจะได้รับประโยชน์จากการแคชข้ามการดำเนินการ คุณอาจต้องใช้ Worker แบบถาวรของคุณเองเพื่อดำเนินการเหล่านี้

เซิร์ฟเวอร์ Bazel สื่อสารกับ Worker โดยใช้ stdin/stdout ซึ่งรองรับการใช้บัฟเฟอร์โปรโตคอลหรือสตริง JSON

การใช้งาน Worker มี 2 ส่วน ดังนี้

การสร้างผู้ปฏิบัติงาน

Worker ที่ทำงานอย่างต่อเนื่องจะปฏิบัติตามข้อกำหนด 2-3 ข้อต่อไปนี้

  • โดยจะอ่านWorkRequestsจากstdin
  • โดยจะเขียน WorkResponses (และเฉพาะ WorkResponses) ไปยัง stdout
  • โดยรับธง --persistent_worker Wrapper ต้องรู้จัก --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 และ สตริงเอาต์พุตที่อธิบายข้อผิดพลาดที่พบในการประมวลผลหรือการดำเนินการ คำขอ ฟิลด์ 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
}

ตามมาตรฐานของ Protobufs คุณไม่จำเป็นต้องกรอกข้อมูลครบทุกช่อง อย่างไรก็ตาม Bazel กำหนดให้ WorkRequest และ WorkResponse ที่เกี่ยวข้องต้องมีรหัสคำขอเดียวกัน ดังนั้นต้องระบุรหัสคำขอหากไม่ใช่ 0 นี่คือ WorkResponse ที่ถูกต้อง

{
  "requestId" : 12,
}

request_id ที่มีค่าเป็น 0 แสดงถึงคำขอ "ซิงเกิลเพล็กซ์" ซึ่งใช้เมื่อประมวลผลคำขอนี้ แบบขนานกับคำขออื่นๆ ไม่ได้ เซิร์ฟเวอร์รับประกันว่า ผู้ปฏิบัติงานที่กำหนดจะได้รับคำขอที่มี request_id 0 เท่านั้นหรือมี request_id มากกว่า 0 เท่านั้น คำขอ Singleplex จะส่งเป็นชุด ตัวอย่างเช่น หากเซิร์ฟเวอร์ไม่ส่งคำขออื่นจนกว่าจะได้รับการตอบกลับ (ยกเว้นคำขอยกเลิก โปรดดูด้านล่าง)

หมายเหตุ

  • แต่ละบัฟเฟอร์โปรโตคอลจะมีคำนำหน้าเป็นความยาวในรูปแบบ 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 ไปยังแฟล็กไฟล์นี้ได้

  • ฟิลด์ "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 compiler workers นอกเหนือจาก example JSON worker ที่ใช้ในการทดสอบการผสานรวม

คุณสามารถใช้โครงสร้างพื้นฐาน เพื่อเปลี่ยนเครื่องมือที่ใช้ Java ให้เป็น Worker ได้โดยส่งการเรียกกลับที่ถูกต้อง

ดูตัวอย่างกฎที่ใช้ Worker ได้ที่การทดสอบการผสานรวม Worker ของ Bazel

ผู้ร่วมให้ข้อมูลภายนอกได้ติดตั้งใช้งาน Worker ในภาษาต่างๆ โปรดดูการติดตั้งใช้งาน Worker แบบถาวรของ Bazel ในหลายภาษา คุณดูตัวอย่างอื่นๆ อีกมากมายได้ใน GitHub