ระบบบิลด์ที่อิงตามอาร์ติแฟกต์

รายงานปัญหา ดูซอร์สโค้ด รุ่น Nightly · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

หน้านี้อธิบายระบบการสร้างที่อิงตามอาร์ติแฟกต์และแนวคิดเบื้องหลังการสร้าง Bazel เป็นระบบการสร้างที่ใช้วัตถุเป็นหลัก ระหว่างบิลด์ตามงาน ระบบนี้ถือเป็นขั้นตอนที่ดี เหนือสคริปต์การสร้าง สคริปต์จะให้ประสิทธิภาพที่มากเกินไปสำหรับ วิศวกรแต่ละคนโดยให้ทีมมอบหมายงานของตัวเอง

ระบบบิลด์ที่อิงตามอาร์ติแฟกต์มีงานจำนวนไม่มากนักที่ระบบกำหนดไว้ ซึ่งวิศวกรสามารถกําหนดค่าได้ในแบบจํากัด วิศวกรยังคงบอกระบบ อะไรที่ควรสร้าง แต่ระบบบิลด์จะเป็นตัวกำหนดวิธีการสร้าง เช่นเดียวกับ ระบบบิลด์ที่อิงตามงาน ระบบบิลด์ที่ใช้อาร์ติแฟกต์ เช่น Bazel มีไฟล์บิลด์ แต่เนื้อหาของไฟล์บิลด์เหล่านั้นแตกต่างกันมาก ไฟล์บิลด์ใน Bazel ไม่ใช่ชุดคำสั่งแบบบังคับในภาษาสคริปต์แบบ Turing-complete ที่อธิบายวิธีสร้างเอาต์พุต แต่เป็นไฟล์ Manifest แบบประกาศที่อธิบายชุดอาร์ติแฟกต์ที่จะสร้าง ไลบรารีที่ใช้ร่วมกัน และชุดตัวเลือกแบบจำกัดที่ส่งผลต่อวิธีสร้าง เมื่อวิศวกรเรียกใช้ bazel ในบรรทัดคำสั่ง พวกเขาจะระบุชุดเป้าหมายที่จะสร้าง (อะไร) และ Bazel รับหน้าที่ในการกำหนดค่า เรียกใช้ และกำหนดเวลาการคอมไพล์ ขั้นตอน (วิธีการ) เพราะตอนนี้ระบบการสร้างสามารถ ควบคุมสิ่งต่างๆ ได้อย่างเต็มที่ ใช้งานเมื่อใด วิธีนี้สามารถรับประกันได้ดีขึ้นมากว่าจะทำให้ มีประสิทธิภาพมากขึ้น ในขณะเดียวกันก็รับประกันความถูกต้อง

มุมมองด้านฟังก์ชันการทำงาน

การเปรียบเทียบระบบบิลด์ที่อิงตามอาร์ติแฟกต์กับการเขียนโปรแกรมเชิงฟังก์ชันนั้นทําได้ง่าย ภาษาโปรแกรมแบบบังคับดั้งเดิม (เช่น Java, C และ Python) จะระบุรายการคำสั่งที่จะดำเนินการทีละรายการ ในลักษณะเดียวกับที่ระบบบิลด์ตามงานช่วยให้โปรแกรมเมอร์กำหนดชุดขั้นตอนที่จะดำเนินการ ในทางตรงกันข้าม ภาษาโปรแกรมเชิงฟังก์ชัน (เช่น Haskell และ ML) จะมีโครงสร้างคล้ายกับชุดสมการทางคณิตศาสตร์มากกว่า ใน โปรแกรมเมอร์จะอธิบายถึงการคำนวณที่จะนำมาใช้งาน แต่ มีรายละเอียดเกี่ยวกับเวลาและวิธีในการดำเนินการคำนวณนั้น คอมไพเลอร์

ซึ่งสอดคล้องกับแนวคิดในการประกาศไฟล์ Manifest ในระบบการบิลด์ที่อิงตามอาร์ติแฟกต์ และปล่อยให้ระบบหาวิธีดำเนินการบิลด์ หลายโจทย์ทำไม่ได้ แสดงออกได้อย่างง่ายดายโดยใช้การเขียนโปรแกรมที่ใช้งานได้ ได้เป็นอย่างดี: ภาษามักจะสามารถ คู่ขนานกันเพียงเล็กน้อย และรับประกันความถูกต้องของโปรแกรมดังกล่าวอย่างเข้มงวด ซึ่งเป็นไปไม่ได้ในภาษาที่จำเป็นต้องใช้ โจทย์ที่เขียนโดยใช้การเขียนโปรแกรมเชิงฟังก์ชันได้ง่ายที่สุดคือโจทย์ที่เกี่ยวข้องกับการเปลี่ยนรูปแบบข้อมูลหนึ่งเป็นรูปแบบอื่นโดยใช้ชุดกฎหรือฟังก์ชัน และนี่คือสิ่งที่ระบบบิลด์เป็น ระบบทั้งระบบเป็นฟังก์ชันทางคณิตศาสตร์ที่รับไฟล์ต้นฉบับ (และเครื่องมือต่างๆ เช่น คอมไพเลอร์) เป็นอินพุตและสร้างไบนารีเป็นเอาต์พุต จึงไม่น่าแปลกใจที่โมเดลนี้สามารถวางรากฐานให้กับงานสร้างได้ดี ระบบพื้นฐานเกี่ยวกับหลักการของการเขียนโปรแกรมเชิงฟังก์ชันการทำงาน

ทำความเข้าใจระบบการสร้างที่อิงตามอาร์ติแฟกต์

Blaze ซึ่งเป็นระบบบิลด์ของ Google เป็นระบบบิลด์ที่อิงตามอาร์ติแฟกต์ระบบแรก บาเซล คือ Blaze เวอร์ชันโอเพนซอร์ส

ไฟล์บิลด์ (ปกติจะตั้งชื่อว่า BUILD) ใน Bazel จะมีลักษณะดังนี้

java_binary(
    name = "MyBinary",
    srcs = ["MyBinary.java"],
    deps = [
        ":mylib",
    ],
)
java_library(
    name = "mylib",
    srcs = ["MyLibrary.java", "MyHelper.java"],
    visibility = ["//java/com/example/myproduct:__subpackages__"],
    deps = [
        "//java/com/example/common",
        "//java/com/example/myproduct/otherlib",
    ],
)

ใน Bazel ไฟล์ BUILD จะกำหนดเป้าหมาย ซึ่งเป้าหมาย 2 ประเภทในที่นี่คือ java_binary และ java_library ทุกเป้าหมายสอดคล้องกับอาร์ติแฟกต์ที่ ที่ระบบสามารถสร้างได้: เป้าหมายไบนารีจะสร้างไบนารีที่สามารถ ดำเนินการโดยตรง และเป้าหมายไลบรารีจะสร้างไลบรารีที่สามารถใช้งานได้โดย ไบนารีหรือไลบรารีอื่นๆ เป้าหมายทุกรายการมีข้อมูลต่อไปนี้

  • name: วิธีอ้างอิงเป้าหมายในบรรทัดคำสั่งและโดยบุคคลอื่น เป้าหมาย
  • srcs: ไฟล์ต้นฉบับที่จะรวบรวมเพื่อสร้างอาร์ติแฟกต์สำหรับเป้าหมาย
  • deps: เป้าหมายอื่นๆ ที่ต้องสร้างขึ้นก่อนเป้าหมายนี้และลิงก์กับ รายการดังกล่าว

ทรัพยากร Dependency อาจอยู่ในแพ็กเกจเดียวกันก็ได้ (เช่น ของ MyBinary ขึ้นอยู่กับ :mylib) หรือแพ็กเกจอื่นในลำดับชั้นของแหล่งที่มาเดียวกัน (เช่น ทรัพยากร Dependency ของ mylib ใน //java/com/example/common)

คุณจะทำการบิลด์โดยใช้เครื่องมือบรรทัดคำสั่งของ Bazel ได้เช่นเดียวกับระบบบิลด์แบบอิงตามงาน หากต้องการสร้างเป้าหมาย MyBinary ให้เรียกใช้ bazel build :MyBinary หลัง ป้อนคำสั่งนั้นเป็นครั้งแรกในที่เก็บเปล่า Bazel ทำดังนี้

  1. แยกวิเคราะห์ไฟล์ BUILD ทั้งหมดในพื้นที่ทํางานเพื่อสร้างกราฟของความสัมพันธ์ระหว่างสิ่งต่างๆ
  2. ใช้กราฟเพื่อระบุทรัพยากร Dependency แบบทรานซิทีฟของ MyBinary นั่น คือ ทุกเป้าหมายที่ MyBinary พึ่งพาและทุกเป้าหมายที่ ขึ้นอยู่กับการเกิดซ้ำ
  3. สร้างการอ้างอิงแต่ละรายการตามลําดับ Bazel จะเริ่มด้วยการสร้างแต่ละเป้าหมายที่ไม่มีทรัพยากรอื่นๆ และติดตามทรัพยากรที่ยังคงต้องสร้างสำหรับแต่ละเป้าหมาย ทันทีที่สร้างทรัพยากร Dependency ทั้งหมดของเป้าหมายแล้ว Bazel จะเริ่มสร้างเป้าหมายนั้น กระบวนการนี้จะดำเนินต่อไปจนกว่าจะมีการสร้างขึ้นทั้งหมดสำหรับ MyBinary ที่เป็น transitive dependency
  4. สร้าง MyBinary เพื่อสร้างไบนารีที่เรียกใช้งานได้ขั้นสุดท้ายซึ่งลิงก์กับข้อกำหนดทั้งหมดที่สร้างไว้ในขั้นตอนที่ 3

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

แต่ประโยชน์ที่ได้มากกว่าการทำงานพร้อมกัน สิ่งที่เห็นได้ชัดอีกอย่างหนึ่งจากแนวทางนี้คือเมื่อนักพัฒนาแอปพิมพ์ bazel build :MyBinary ครั้งที่สองโดยไม่มีการเปลี่ยนแปลงใดๆ Bazel จะออกในพริบตาพร้อมข้อความว่าเป้าหมายเป็นเวอร์ชันล่าสุด นี่คือ ได้เพราะกระบวนทัศน์การเขียนโปรแกรมเชิงฟังก์ชันการทำงานที่เราพูดถึง ก่อนหน้านี้ Bazel รู้ว่าแต่ละเป้าหมายเป็นผลลัพธ์จากการเรียกใช้ Java เพียงอย่างเดียว และรู้ว่าเอาต์พุตจากคอมไพเลอร์ Java ขึ้นอยู่กับ อินพุต ตราบใดที่อินพุตไม่มีการเปลี่ยนแปลง เอาต์พุตก็จะใช้ซ้ำได้ และการวิเคราะห์นี้จะทำงานในทุกระดับ หาก MyBinary.java มีการเปลี่ยนแปลง Bazel จะรู้ว่าต้องสร้าง MyBinary ขึ้นมาใหม่ แต่ใช้ mylib ซ้ำ หากไฟล์ต้นฉบับของ //java/com/example/common มีการเปลี่ยนแปลง Bazel จะรู้ว่าต้องสร้างไลบรารี //java/com/example/common, mylib และ MyBinary ขึ้นมาใหม่ แต่ใช้ //java/com/example/myproduct/otherlib ซ้ำ เนื่องจาก Bazel ทราบเกี่ยวกับพร็อพเพอร์ตี้ของเครื่องมือที่ทำงานในทุกขั้นตอน จึงสามารถสร้างอาร์ติแฟกต์ชุดน้อยที่สุดได้ทุกครั้งโดยรับประกันว่าจะไม่สร้างบิลด์ที่ล้าสมัย

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

เคล็ดลับอื่นๆ ของ Bazel

ระบบการสร้างที่ใช้วัตถุเป็นหลักจะช่วยแก้ปัญหาการทำงานควบคู่กันไป และการใช้งานซ้ำในระบบบิลด์ที่อิงตามงาน แต่ยังคงมี มีปัญหา 2-3 ข้อก่อนหน้านี้ซึ่งเรายังไม่ได้จัดการ Bazel ฉลาด วิธีแก้ปัญหาแต่ละแบบ และเราควรหารือกันก่อนที่จะดำเนินการต่อ

เครื่องมือที่เป็นทรัพยากร Dependency

ปัญหาหนึ่งที่เราเจอก่อนหน้านี้คือเวอร์ชันต่างๆ ขึ้นอยู่กับเครื่องมือที่ติดตั้งไว้ บนเครื่องของเรา และการสร้างบิลด์ซ้ำทั่วทั้งระบบก็อาจเป็นเรื่องยากเนื่องจาก เวอร์ชันเครื่องมือหรือตำแหน่งต่างๆ ปัญหาจะยิ่งยากขึ้นเมื่อโปรเจ็กต์ใช้ภาษาที่ต้องใช้เครื่องมือที่แตกต่างกันตามแพลตฟอร์มที่ใช้สร้างหรือคอมไพล์ (เช่น Windows กับ Linux) และแต่ละแพลตฟอร์มต้องใช้ชุดเครื่องมือที่แตกต่างกันเล็กน้อยในการทำงานเดียวกัน

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

Bazel แก้ปัญหาส่วนที่ 2 ซึ่งเป็นแพลตฟอร์มอิสระด้วยการตั้งค่าการกำหนดค่าการสร้าง เป้าหมายจะขึ้นอยู่กับประเภทการกําหนดค่า ไม่ใช่เครื่องมือโดยตรง ดังนี้

  • การกำหนดค่าโฮสต์: เครื่องมือสร้างที่ทำงานระหว่างการสร้าง
  • การกำหนดค่าเป้าหมาย: การสร้างไบนารีที่คุณร้องขอในท้ายที่สุด

การขยายระบบบิลด์

Bazel มีเป้าหมายสำหรับภาษาโปรแกรมยอดนิยมหลายภาษาตั้งแต่เริ่มต้น แต่วิศวกรก็ต้องการทําสิ่งอื่นๆ เพิ่มเติมอยู่เสมอ ประโยชน์ส่วนหนึ่งของระบบที่อิงตามงานคือความยืดหยุ่นในการสนับสนุนกระบวนการบิลด์ทุกประเภท และคุณไม่ควรละทิ้งข้อดีนี้ในระบบบิลด์ที่อิงตามอาร์ติแฟกต์ แต่โชคดีที่ Bazel อนุญาตให้ขยายประเภทเป้าหมายที่รองรับได้โดยการเพิ่มกฎที่กำหนดเอง

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

ระบบไม่ได้เด็ดขาดเพราะไม่มีวิธีหยุดนักพัฒนาแอปการดำเนินการ จากการดำเนินการบางอย่าง เช่น การนำกระบวนการที่ไม่เจาะจงซึ่งเป็นส่วนหนึ่งของ การกระทำของพวกเขา แต่วิธีนี้ไม่ได้เกิดขึ้นบ่อยนัก และการผลักดันให้ ความเป็นไปได้ของการละเมิดไปจนถึงระดับการดำเนินการลดลงอย่างมาก โอกาสเกิดข้อผิดพลาด กฎที่รองรับภาษาและเครื่องมือทั่วไปจำนวนมากมีให้บริการทางออนไลน์อย่างแพร่หลาย และโปรเจ็กต์ส่วนใหญ่จะไม่จำเป็นต้องกำหนดกฎของตนเอง แม้กระทั่งสำหรับทีมที่ใช้ เพียงต้องกำหนดคำจำกัดความของกฎในที่ส่วนกลางที่เดียวในที่เก็บ ซึ่งหมายความว่าวิศวกรส่วนใหญ่จะใช้กฎเหล่านั้นได้โดยไม่ต้องกังวลเกี่ยวกับการใช้งาน

การแยกสภาพแวดล้อม

การดำเนินการต่างๆ อาจดูเหมือนพบปัญหาเดียวกันกับงานอื่นๆ เป็นไปไม่ได้ใช่ไหมที่จะเขียนการทำงานที่ทั้ง 2 อย่างนี้เขียนเหมือนกัน แล้วเกิดการขัดแย้งกันได้อย่างไร อันที่จริง Bazel ป้องกันความขัดแย้งเหล่านี้ได้โดยใช้แซนด์บ็อกซ์ รองรับใน การดำเนินการทุกอย่างจะแยกออกจากการดำเนินการอื่นๆ ทั้งหมดผ่านระบบไฟล์ แซนด์บ็อกซ์ การดำเนินการแต่ละรายการจึงมองเห็นได้เฉพาะมุมมองที่จำกัดของไฟล์ระบบซึ่งมีอินพุตที่ประกาศไว้และเอาต์พุตที่สร้างขึ้น ซึ่งระบบต่างๆ เช่น LXC ใน Linux ซึ่งเป็นเทคโนโลยีเดียวกับที่อยู่เบื้องหลัง Docker จะบังคับใช้ ซึ่งหมายความว่าการดำเนินการต่างๆ จะไม่ขัดแย้งกัน เนื่องจากการดำเนินการจะอ่านไฟล์ที่ไม่ได้ประกาศไม่ได้ และระบบจะทิ้งไฟล์ที่เขียนแต่ไม่ได้ประกาศเมื่อการดำเนินการเสร็จสิ้น นอกจากนี้ Bazel ยังใช้แซนด์บ็อกซ์เพื่อจำกัดการทำงานจากการสื่อสารผ่านทาง เครือข่าย

การกำหนดทรัพยากร Dependency ภายนอก

แต่ยังคงมีปัญหาอีกอย่างหนึ่งอยู่ ซึ่งก็คือระบบบิลด์มักจะต้องดาวน์โหลดข้อกำหนดเบื้องต้น (ไม่ว่าจะเป็นเครื่องมือหรือไลบรารี) จากแหล่งที่มาภายนอกแทนที่จะสร้างโดยตรง ซึ่งสามารถดูได้ในตัวอย่างผ่านทาง ทรัพยากร Dependency @com_google_common_guava_guava//jar ซึ่งดาวน์โหลดไฟล์ JAR จาก Maven

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

ปัญหาพื้นฐานคือเราอยากให้ระบบบิลด์ตระหนักถึงสิ่งเหล่านี้ ไฟล์โดยไม่ต้องตรวจสอบในการควบคุมแหล่งที่มา การอัปเดตทรัพยากร Dependency ควรเป็นทางเลือกที่พิจารณาอย่างรอบคอบ แต่ควรเลือกเพียงครั้งเดียวในตำแหน่งส่วนกลางแทนที่จะให้วิศวกรแต่ละคนจัดการหรือให้ระบบจัดการโดยอัตโนมัติ นั่นเป็นเพราะถึงแม้ว่าจะมีโมเดล "Live at Head" แล้ว เราก็ยังต้องการสิ่งที่สร้าง ที่จะตัดสินใจ ซึ่งก็หมายความว่าหากคุณตรวจสอบการคอมมิตจาก คุณควรเห็นทรัพยากร Dependency ตามที่เป็น ณ ขณะนั้น ไม่ใช่ กันเลย

Bazel และระบบบิลด์อื่นๆ ช่วยแก้ปัญหานี้โดยกำหนดให้ ไฟล์ Manifest ของทั้งพื้นที่ทํางานที่แสดงแฮชแบบเข้ารหัสสําหรับภายนอกทั้งหมด ทรัพยากร Dependency ในพื้นที่ทำงาน แฮชจึงเป็นวิธีที่สั้นกระชับในการแสดงถึง ไฟล์โดยไม่ต้องตรวจสอบทั้งไฟล์ลงในการควบคุมแหล่งที่มา เมื่อใดก็ตามที่มีการอ้างอิงถึงข้อกําหนดภายนอกใหม่จากพื้นที่ทํางาน ระบบจะเพิ่มแฮชของข้อกําหนดนั้นลงในไฟล์ Manifest ด้วยตนเองหรือโดยอัตโนมัติ เมื่อ Bazel เรียกใช้ โมเดลดังกล่าวจะตรวจสอบแฮชจริงของทรัพยากร Dependency ที่แคชไว้กับรายการที่คาดไว้ แฮชที่กำหนดไว้ในไฟล์ Manifest และดาวน์โหลดไฟล์อีกครั้งเฉพาะเมื่อแฮชแตกต่างกันเท่านั้น

หากอาร์ติแฟกต์ที่เราดาวน์โหลดมีแฮชต่างจากที่ประกาศใน ไฟล์ Manifest การสร้างจะล้มเหลวเว้นแต่จะมีการอัปเดตแฮชในไฟล์ Manifest ซึ่งทําได้โดยอัตโนมัติ แต่การเปลี่ยนแปลงดังกล่าวต้องได้รับการอนุมัติและตรวจสอบในระบบควบคุมแหล่งที่มาก่อน บิลด์จึงจะยอมรับข้อกําหนดใหม่ ซึ่งหมายความว่าจะมีบันทึกเวลาที่อัปเดตทรัพยากรภายนอกอยู่เสมอ และทรัพยากรภายนอกจะเปลี่ยนแปลงไม่ได้หากไม่มีการเปลี่ยนแปลงที่สอดคล้องกันในแหล่งที่มาของพื้นที่ทำงาน และยังหมายความว่า เมื่อคุณดูซอร์สโค้ดรุ่นเก่า รหัส ได้รับการรับประกันว่าบิลด์จะใช้ทรัพยากร Dependency เดียวกันกับที่บิลด์นั้นใช้อยู่ เมื่อเช็คอินเวอร์ชันนั้นแล้ว (ไม่เช่นนั้นก็จะล้มเหลวหากทรัพยากร Dependency เหล่านี้ ไม่มีให้บริการอีกต่อไป)

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