Menekan Terbitkan Dua Kali Kini Hanya Menerbitkan Sekali
Tiga permintaan penerbitan untuk apl yang sama tiba di API kami dengan jarak 84 milisaat, dan setiap satu memulakan deployment penuh bagi apl itu. Mereka berlumba antara satu sama lain ke hosting yang sama, beberapa keluaran yang terhasil gagal kerana yang lain telah sampai dahulu, dan satu-satunya tanda yang kelihatan ialah e-mel “keluaran gagal” — apl itu sendiri akhirnya berjaya. Kini penerbitan yang tiba semasa penerbitan lain sedang berjalan untuk apl yang sama tidak memulakan binaan kedua. Pangkalan data memutuskan permintaan mana yang menang, dan yang lain diberitahu perkara sebenar: satu penerbitan sudah berjalan.
Apa yang berlaku
Apabila anda menerbitkan apl di Mythex, API merekodkan satu deployment untuknya dan meminta orkestrator kami — perkhidmatan yang menjalankan binaan — untuk membina dan mengeluarkannya. Penerbitan boleh bermula dari butang Terbitkan, dari tab pelayar lain, atau dari ejen apabila anda memintanya menerbitkan. Klik dua kali, dua tab, atau permintaan ejen yang tiba dua kali semuanya boleh menghasilkan lebih daripada satu penerbitan bagi apl yang sama hampir pada masa yang sama.
Dalam kes ini, tiga tiba dalam masa 84 ms. Setiap satu menjalankan deployment penuh. Di platform hosting, keluaran bagi apl yang sama dicipta dalam saat yang sama, dan tiga daripadanya gagal kerana yang lain sudah berjalan. Satu keluaran kemudian tersekat, dan apl itu berfungsi selepas itu.
Ini yang menjadikannya mudah terlepas pandang. Pengguna melihat satu apl yang berfungsi. Kegagalan hanya muncul sebagai e-mel kegagalan keluaran.
Mengapa tiada apa yang menghalangnya
Kod penerbitan memang mempunyai satu langkah yang melihat deployment yang sedang berjalan untuk projek itu. Tetapi apa yang dilakukannya ialah menandakan setiap deployment yang sedang berjalan sebagai gagal sebelum memulakan — “digantikan oleh penerbitan baharu”. Ia bertujuan membersihkan binaan yang ditinggalkan oleh proses yang ranap.
Dalam amalan, ia bermakna penerbitan kedua yang tiba di tengah-tengah binaan mengisytiharkan yang pertama sudah mati dan memulakan binaannya sendiri. Kedua-duanya berjalan hingga selesai terhadap apl yang sama. Tiada kunci; yang ada ialah langkah yang secara aktif membuka laluan untuk perlumbaan.
Ada gejala kedua yang lebih ganjil untuk penerbitan pertama sesuatu apl. Tanpa rekod deployment untuk digunakan semula, dua penerbitan pertama serentak kedua-duanya cuba memasukkan satu rekod. Pangkalan data mempunyai indeks unik pada nama pautan apl (slugnya, seperti your-app dalam your-app.mythex.ai), jadi sisipan kedua gagal. API menterjemahkannya kepada “nama pautan itu telah diambil” — menasihati pengguna supaya menamakan semula apl yang pada masa itu sedang berjaya diterbitkan di bawah nama tersebut.
Pembetulan: tuntutan itu ialah kunci
Menuntut rekod deployment kini adalah satu kemas kini pangkalan data bersyarat tunggal: ambil baris ini dan tandakan sebagai sedang membina hanya jika tiada siapa sedang menerbitkannya. Kerana ia satu pernyataan, pangkalan data menyelesaikan permintaan yang tiba dalam milisaat yang sama. Tepat satu daripadanya mengubah baris itu. Yang lain melihat bahawa sifar baris berubah, berhenti, dan tidak sekali-kali sampai ke orkestrator.
Kunci juga memerlukan jalan keluar apabila pemegangnya mati. Jika API dimulakan semula di tengah-tengah penerbitan, baris itu akan kekal ditandakan “sedang membina” selamanya dan apl tidak boleh diterbitkan. Jadi baris yang pemiliknya tidak lagi menghantar isyarat denyut — penerbitan yang sedang berjalan mengemas kini baris setiap 30 saat, dan lima minit senyap dikira sebagai mati — boleh dituntut semula. Ambang itu datang daripada denyut, bukan daripada tekaan berapa lama binaan patut mengambil masa. Membina Dockerfile sendiri pengguna memang boleh mengambil masa yang lama, dan binaan yang perlahan tetapi masih berdenyut mengekalkan tuntutannya.
Langkah yang dahulu menggagalkan setiap deployment yang sedang berjalan tidak lagi dijalankan sebelum penerbitan. Hanya baris yang ditinggalkan oleh proses yang mati dibersihkan.
Memberitahu pihak yang kalah perkara sebenar
Permintaan yang kalah kini mendapat jawapan yang jelas: publish_in_progress, bersama ID deployment yang sedang berjalan. Setiap tempat yang boleh memulakan penerbitan mengendalikannya:
- Ruang kerja mengikuti binaan yang sudah berjalan dan bukannya memaparkan ralat di atasnya.
- Ejen diberitahu bahawa penerbitan apl ini sudah berjalan dan supaya menunggu, dan bukannya diberitahu bahawa sesuatu gagal — yang sebelum ini boleh menyebabkannya pergi “membetulkan” Dockerfile dan mencuba semula.
- Pertembungan penerbitan pertama pada nama pautan disemak: jika baris yang memegang nama itu ialah penerbitan yang sedang berjalan bagi projek ini sendiri, jawapannya ialah “sedang menerbitkan”, bukan “nama itu telah diambil”. Pertembungan sebenar dengan projek lain masih menerima mesej tukar nama.
Cara kami menyemaknya
Kami menulis skrip penghasilan semula yang menjalankan tiga penerbitan bagi satu apl serentak terhadap pangkalan data sebenar dan orkestrator olok-olok, dan mengira berapa banyak deployment yang diminta daripada orkestrator. Ia meliputi penerbitan pertama dan penerbitan semula bagi apl yang sedang hidup. Sebelum pembetulan, ia mengira dua deployment. Selepas itu, satu.
Skrip itu juga meliputi laluan keluar: ia menandakan baris apl sebagai sedang membina tanpa denyut selama sepuluh minit, menerbitkan semula, dan memeriksa bahawa penerbitan baharu menuntut baris itu dan berjalan.
Ujian unit mengekalkan kunci kepada dua perkara yang mesti dilakukan oleh kunci: daripada tiga penerbitan semula serentak, tepat satu berjaya lepas dan dua lagi diberitahu bahawa penerbitan sedang berjalan; dan binaan yang pemiliknya telah mati boleh dituntut. Ujian lain menyemak bahawa percubaan baharu tidak membawa mesej ralat percubaan sebelumnya.
Apa yang kami pelajari
- Kod pembersihan boleh menjadi perlumbaan yang menyamar. “Gagalkan apa sahaja yang sedang berjalan, kemudian mulakan” kelihatan seperti kebersihan. Dengan dua pemanggil, ia adalah setiap satu membatalkan yang lain.
- Biarkan pangkalan data menjadi penimbang. Bacaan diikuti tulisan meninggalkan jurang untuk permintaan lain. Satu kemas kini bersyarat tunggal tidak.
- Setiap kunci memerlukan tempoh tamat yang berkait dengan kehidupan. Tanpanya, ranap bertukar menjadi apl yang tersekat.
- Mesej ralat ialah arahan. “Nama itu telah diambil” menyuruh orang melakukan perkara yang salah. Mesej yang betul lebih ringkas dan benar.
Lebih lanjut tentang penerbitan dalam dokumentasi: cara menerbitkan. Dan satu pembetulan berkaitan: apl yang diterbitkan kekal aktif semasa anda menerbitkannya semula.