บล็อก

กดเผยแพร่สองครั้งตอนนี้เผยแพร่เพียงครั้งเดียว

คำขอเผยแพร่สามรายการสำหรับแอปเดียวกันมาถึง API ของเราห่างกัน 84 มิลลิวินาที และแต่ละรายการเริ่มการดีพลอยเต็มรูปแบบของแอปนั้น ทั้งหมดแข่งกันขึ้นไปยังโฮสติ้งเดียวกัน หลายรีลีสที่เกิดขึ้นล้มเหลวเพราะมีอีกรายการไปถึงก่อนแล้ว และสัญญาณเดียวที่มองเห็นได้คืออีเมล “release failed” ส่วนแอปเองสุดท้ายก็ทำงานได้ดี ตอนนี้การเผยแพร่ที่มาถึงในขณะที่อีกรายการกำลังทำงานให้แอปเดียวกันจะไม่เริ่มการสร้างครั้งที่สอง ฐานข้อมูลเป็นตัวตัดสินว่าคำขอไหนชนะ และรายการอื่นจะได้รับแจ้งความจริง: มีการเผยแพร่ที่กำลังทำงานอยู่แล้ว

เกิดอะไรขึ้น

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

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

นั่นคือสิ่งที่ทำให้มองข้ามได้ง่าย ผู้ใช้เห็นแอปที่ทำงานได้หนึ่งแอป ความล้มเหลวปรากฏเฉพาะในอีเมล release-failure

ทำไมไม่มีอะไรหยุดมัน

โค้ดการเผยแพร่มีขั้นตอนที่ดูการดีพลอยที่กำลังดำเนินการอยู่สำหรับโปรเจกต์ แต่สิ่งที่มันทำคือทำเครื่องหมายทุกการดีพลอยที่กำลังดำเนินการว่าล้มเหลวก่อนเริ่ม ด้วยเหตุผล “แทนที่ด้วยการเผยแพร่ใหม่” มันตั้งใจไว้เพื่อเก็บกวาดการสร้างที่ค้างอยู่หลังจากโปรเซสที่พังไป

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

มีอาการที่สองและแปลกกว่าสำหรับการเผยแพร่ครั้งแรกของแอป เมื่อยังไม่มีบันทึกการดีพลอยให้ใช้ซ้ำ การเผยแพร่ครั้งแรกสองครั้งพร้อมกันจะพยายามแทรกหนึ่งรายการเดียวกัน ฐานข้อมูลมี unique index บนชื่อลิงก์ของแอป (slug เช่น your-app ใน your-app.mythex.ai) ดังนั้นการแทรกที่สองล้มเหลว API แปลสิ่งนั้นเป็น “ชื่อลิงก์นั้นถูกใช้แล้ว” ซึ่งแนะนำให้ผู้ใช้เปลี่ยนชื่อแอปที่กำลังเผยแพร่สำเร็จภายใต้ชื่อนั้นในขณะนั้น

การแก้ไข: การอ้างสิทธิ์คือ lock

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

lock ก็ต้องมีทางออกเมื่อผู้ถือตายด้วย ถ้า API รีสตาร์ทกลางการเผยแพร่ แถวจะค้างอยู่ที่ “กำลังสร้าง” ตลอดไปและแอปจะเผยแพร่ไม่ได้ ดังนั้นแถวที่เจ้าของหยุดส่ง heartbeat จึงอ้างสิทธิ์ซ้ำได้ การเผยแพร่ที่กำลังทำงานจะอัปเดตแถวทุก 30 วินาที และความเงียบห้านาทีนับว่าตาย เกณฑ์นั้นมาจาก heartbeat ไม่ใช่การเดาว่าการสร้างใช้เวลานานแค่ไหน การสร้าง Dockerfile ของผู้ใช้เองอาจใช้เวลานานได้อย่างชอบธรรม และการสร้างที่ช้าแต่ยังส่ง heartbeat จะรักษาการอ้างสิทธิ์ไว้

ขั้นตอนที่ทำให้การดีพลอยที่กำลังดำเนินการทั้งหมดล้มเหลวจะไม่รันก่อนการเผยแพร่อีกต่อไป จะเคลียร์เฉพาะแถวที่โปรเซสที่ตายทิ้งไว้เท่านั้น

บอกผู้แพ้อย่างตรงไปตรงมา

คำขอที่แพ้ตอนนี้จะได้คำตอบที่ชัดเจน: publish_in_progress พร้อม ID ของการดีพลอยที่กำลังทำงาน ทุกจุดที่เริ่มการเผยแพร่ได้จัดการเรื่องนี้:

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

วิธีที่เราตรวจสอบ

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

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

unit test ยึด lock กับสองสิ่งที่ lock ต้องทำ: จากการเผยแพร่ซ้ำพร้อมกันสามรายการ มีเพียงหนึ่งที่ผ่านได้ และอีกสองรายการจะได้รับแจ้งว่ามีการเผยแพร่กำลังทำงาน และการสร้างที่เจ้าของตายแล้วสามารถถูกอ้างสิทธิ์ได้ การทดสอบอีกรายการตรวจว่าความพยายามใหม่ไม่รับข้อความข้อผิดพลาดของความพยายามก่อนหน้าไปด้วย

สิ่งที่เราได้เรียนรู้

  • โค้ดเก็บกวาดอาจเป็นการแข่งขันที่ซ่อนอยู่ “ล้มเหลวทุกอย่างที่กำลังทำงานแล้วค่อยเริ่ม” ดูเหมือนการรักษาความสะอาด แต่เมื่อมีผู้เรียกสองราย มันคือการที่แต่ละรายยกเลิกอีกราย
  • ให้ฐานข้อมูลเป็นผู้ตัดสิน การอ่านแล้วตามด้วยการเขียนเปิดช่องว่างให้คำขออื่น ส่วนการอัปเดตแบบมีเงื่อนไขคำสั่งเดียวไม่มี
  • ทุก lock ต้องมีการหมดอายุที่ผูกกับการยังมีชีวิต ถ้าไม่มี การล่มจะกลายเป็นแอปที่ค้างตลอดไป
  • ข้อความข้อผิดพลาดคือคำสั่ง “ชื่อนั้นถูกใช้แล้ว” บอกให้คนทำสิ่งที่ผิด ข้อความที่ถูกต้องคือข้อความที่ง่ายกว่าและเป็นความจริง

เอกสารเรื่องการเผยแพร่: วิธีเผยแพร่ และการแก้ไขที่เกี่ยวข้อง: แอปที่เผยแพร่แล้วยังคงออนไลน์ระหว่างที่คุณเผยแพร่ซ้ำ

Mythex · Pricing · สร้างอะไรก็ได้ด้วย AI · เทมเพลตเว็บไซต์และแอป · เปรียบเทียบ Mythex · อภิธานศัพท์การสร้างแอปด้วย AI · เครื่องมือฟรีสำหรับสร้างแอปด้วย AI · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)