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

รายงานปัญหา ดูแหล่งที่มา

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

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

มุมมองที่ใช้งานได้

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

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

ทําความเข้าใจระบบบิวด์ที่ใช้อาร์ติแฟกต์

Blaze เป็นระบบบิวด์ของ Google เป็นระบบบิวด์ที่ใช้วัตถุแรก Bazel เป็น 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 อาจอยู่ในแพ็กเกจเดียวกัน (เช่น ทรัพยากร Dependency ของ MyBinary ใน :mylib) หรือในแพ็กเกจอื่นในลําดับชั้นต้นทางเดียวกัน (เช่น mylib ทรัพยากร Dependency ของ //java/com/example/common)

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

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

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

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

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

เคล็ดลับ Bazel เจ๋งๆ

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

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

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

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

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

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

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

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

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

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

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

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

การทําให้ทรัพยากร Dependency ภายนอกกําหนด

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

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

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

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

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

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