Publish’e İki Kez Basmak Artık Tek Yayınlıyor
Aynı uygulama için üç yayın isteği API’mize 84 milisaniye arayla ulaştı ve her biri o uygulamanın tam bir dağıtımını başlattı. Aynı barındırmaya birbirleriyle yarıştılar; ortaya çıkan sürümlerin birkaçı, başka biri daha önce varmış olduğu için başarısız oldu ve tek görünür işaret bir “release failed” e-postasıydı — uygulamanın kendisi sonunda sorunsuzdu. Artık, aynı uygulama için çalışan bir yayın varken gelen bir yayın ikinci bir derleme başlatmaz. Hangi isteğin kazanacağına veritabanı karar verir ve diğerlerine gerçek söylenir: bir yayın zaten çalışıyor.
Ne oldu
Mythex’te bir uygulamayı yayınladığınızda API o uygulama için bir dağıtım kaydı oluşturur ve derlemeleri çalıştıran servis olan orkestratöre, derleyip yayınlamasını ister. Yayın, Publish düğmesinden, başka bir tarayıcı sekmesinden ya da bunu istediğinizde agentten başlayabilir. Çift tıklama, iki sekme ya da iki kez gelen bir agent isteği, neredeyse aynı anda aynı uygulama için birden fazla yayın üretebilir.
Bu durumda üçü 84 ms içinde geldi. Her biri tam bir dağıtım çalıştırdı. Barındırma platformunda aynı uygulamanın sürümleri aynı saniyede oluşturuldu ve üçünden bazıları, diğerleri zaten ilerlediği için başarısız oldu. Sonraki bir sürüm takıldı, ama uygulama sonrasında çalıştı.
Bu, gözden kaçmasını kolaylaştıran şeydi. Kullanıcı tek bir çalışan uygulama gördü. Hatalar yalnızca “release failed” e-postalarında göründü.
Neden hiçbir şey durdurmadı
Yayın kodunun, projenin devam eden dağıtımlarına bakan bir adımı vardı. Ama bu adım, başlamadan önce devam eden her dağıtımı başarısız olarak işaretliyordu — “yeni bir yayın tarafından geçersiz kılındı”. Çöken bir süreçten kalan derlemeleri temizlemek için tasarlanmıştı.
Pratikte bu, yayın sırasında gelen ikinci bir yayının ilkini ölü ilan edip kendi yayınını başlatması demekti. İkisi de aynı uygulamaya karşı sonuna kadar çalışıyordu. Hiçbir kilit yoktu; yarışı aktif olarak açan bir adım vardı.
Bir uygulamanın ilk yayınında ikinci, daha garip bir belirti vardı. Yeniden kullanılacak bir dağıtım kaydı henüz yokken, eşzamanlı iki ilk yayın ikisi de birini eklemeye çalışıyordu. Veritabanında uygulamanın bağlantı adı (slug’ı, your-app.mythex.ai içindeki your-app gibi) üzerinde benzersiz bir indeks var, bu yüzden ikinci ekleme başarısız oldu. API bunu “bu bağlantı adı alınmış” olarak çevirdi — o anda o adla başarıyla yayınlanmakta olan bir uygulamayı yeniden adlandırmayı önererek.
Düzeltme: talep kilidin ta kendisidir
Bir dağıtım kaydını talep etmek artık tek bir koşullu veritabanı güncellemesidir: bu satırı al ve yalnızca kimse yayınlamıyorsa derleniyor olarak işaretle. Tek bir ifade olduğu için veritabanı aynı milisaniyede gelen istekleri çözer. Tam olarak biri satırı değiştirir. Diğerleri hiçbir satırın değişmediğini görür, durur ve orkestratöre hiç ulaşmaz.
Bir kilidin sahibi öldüğünde çıkışa da ihtiyacı vardır. API bir yayının ortasında yeniden başlarsa, satır sonsuza dek “derleniyor” olarak kalır ve uygulama yayınlanamaz hale gelir. Bu yüzden, sahibi kalp atışı göndermeyi bırakmış bir satır — çalışan yayın satırı her 30 saniyede bir günceller ve beş dakika sessizlik ölü sayılır — yeniden talep edilebilir. Bu eşik bir tahminden değil, kalp atışından gelir. Kullanıcının kendi Dockerfile’ını derlemek meşru olarak uzun sürebilir ve kalp atışı gönderen yavaş bir derleme talebini korur.
Bir yayın öncesinde devam eden her dağıtımı başarısız yapan adım artık çalışmaz. Yalnızca geride kalmış bir ölü sürecin bıraktığı satırlar temizlenir.
Kaybedene gerçeği söylemek
Kaybeden istek artık açık bir cevap alır: publish_in_progress, çalışan dağıtımın kimliğiyle birlikte. Yayın başlatabilen her yer bunu ele alır:
- Çalışma alanı, bir hata göstermek yerine zaten çalışan derlemeyi takip eder.
- Agente, bu uygulamanın bir yayınının zaten çalıştığı ve onu beklemesi gerektiği söylenir; daha önce bir şeyin başarısız olduğu söylenirdi — bu da onu bir Dockerfile’ı “düzeltmeye” ve yeniden denemeye yönlendirebilirdi.
- Bağlantı adındaki ilk yayın çakışması kontrol edilir: adı tutan satır projenin kendi çalışan yayınıysa, cevap “zaten yayınlanıyor”dur, “bu ad alınmış” değil. Başka bir projeyle gerçek bir çakışma hâlâ yeniden adlandırma mesajını alır.
Nasıl doğruladık
Gerçek bir veritabanı ve sahte bir orkestratör karşısında, aynı uygulama için üç yayını aynı anda çalıştıran ve orkestratörden kaç dağıtım istendiğini sayan bir yeniden üretim betiği yazdık. Bir ilk yayını ve canlı bir uygulamanın yeniden yayınını kapsar. Düzeltmeden önce iki dağıtım sayıldı. Sonrasında bir.
Betik ayrıca kaçış yolunu da kapsar: uygulamanın satırını on dakika boyunca kalp atışsız derleniyor olarak işaretler, yeniden yayınlar ve yeni yayının satırı talep edip çalıştığını kontrol eder.
Birim testleri kilide iki şeyi yapması için bağlar: aynı anda üç yeniden yayından tam olarak biri geçer ve diğer ikisine bir yayının çalıştığı söylenir; ve sahibi ölmüş bir derleme talep edilebilir. Başka bir test, yeni bir denemenin önceki denemenin hata mesajını taşımadığını kontrol eder.
Bundan çıkardıklarımız
- Temizlik kodu gizli bir yarış olabilir. “Devam edeni başarısız yap, sonra başlat” temizlik gibi okunur. İki çağıran olduğunda, her biri diğerini iptal eder.
- Kilidi veritabanına bırakın. Önce okuyup sonra yazmak, başka bir isteğe boşluk bırakır. Tek bir koşullu güncelleme bırakmaz.
- Her kilidin canlılığa bağlı bir süresi olmalıdır. Yoksa bir çökme, takılı kalmış bir uygulamaya dönüşür.
- Hata mesajları talimattır. “Bu ad alınmış” insanlara yanlış şeyi yapmalarını söylüyordu. Doğru mesaj daha basitti ve gerçekti.
Yayınlama hakkında daha fazlası dokümanlarda: nasıl yayınlanır. İlgili bir düzeltme: yayınlanmış uygulamanız yeniden yayınlarken ayakta kalır.