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

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

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

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

การสร้าง Worker

Persistent Worker ต้องเป็นไปตามข้อกำหนดต่อไปนี้

  • โดยจะอ่าน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 จะส่งออกอะไรและอย่างไร ค่าที่สูงขึ้น แสดงว่าเอาต์พุตมีรายละเอียดมากขึ้น การส่งแฟล็ก --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" ซึ่งใช้เมื่อคำขอนี้ ประมวลผลแบบขนานกับคำขออื่นๆ ไม่ได้ เซิร์ฟเวอร์รับประกันว่า Worker ที่กำหนดจะได้รับคำขอที่มี 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 ต้องมีฟิลด์ที่อ้างอิงถึง 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