Health check tasarlamak: Liveness ve readiness ayrımı

Uygulamanın canlılığını ve veritabanıyla işe hazır olmasını ayrı ölçen iki kontrol

Veritabanı kesilince uygulamayı yeniden başlatmak her zaman sorunu çözmez. Process ayaktadır ama yeni iş yapamıyordur. Aynı hatayı liveness’a bağladıysak bütün instance’lar tekrar tekrar başlayıp aynı bağlantıyı denemeye devam edebilir. Health check’i yazmadan önce sonucunun hangi kararı tetikleyeceğini bilmek gerekiyor: process yeniden mi başlatılacak, yoksa yalnız yeni trafik mi kesilecek? Liveness ve readiness ayrımını bu davranış üzerinden kurabiliriz.

Örnekte bir cihaz yönetim API’si var. Uygulama açılıyor, HTTP isteğine yanıt verebiliyor; fakat veritabanı bağlantısı henüz hazır değil. Load balancer’ın bu instance’a yeni iş göndermemesini isteyebiliriz. Buna karşılık process’i hemen öldürmek istemeyebiliriz. Bu iki ihtiyaç için aynı sağlıklı kelimesini kullanmak, izlemenin anlamını belirsizleştirir. Endpoint’in adı kadar onu tüketen sistemin davranışı da önemlidir.

Kod ASP.NET Core 8’in HealthChecks altyapısını kullanıyor. Veritabanı örneği EF Core 8 ve SQL Server provider’ıyla kurulabilir. Burada Kubernetes’e özel bir zorunluluk yok; aynı ayrım farklı orchestrator veya load balancer düzenlerinde de uygulanabilir. Ancak kontrolü tüketen sistemin hangi HTTP sonucunda ne yapacağı kendi yapılandırmasından doğrulanmalı. Bir URL açmak tek başına trafik yönetimi kurmaz.

Kontrolün sorusu ile vereceğimiz tepkiyi eşleştirmek

Liveness için ilk soru process’in yanıt verebilen bir uygulama olarak çalışıp çalışmadığı olabilir. Readiness ise bu instance’ın yeni iş kabul etmesi için gerekli koşulları sorar. Bu iki kontrolü bütün iç kaynakların kusursuz olduğunu kanıtlayan genel testler gibi kullanmak doğru değildir. İkisi de sınırlı bir gözlem sağlar. Hangi durumu kapsadıkları bilinirse sonuçlarına uygun tepki verilebilir.

Veritabanına erişilemezken readiness başarısız, liveness başarılı kalabilir. İki yanıt farklı sorulara cevap verdiği için burada çelişki yok. Öte yandan basit HTTP yanıtı veren liveness, kritik worker döngüsünün durduğunu görmeyebilir. Kontrole ne ekleyeceğimizi, başarısızlığında ne yapılmasını istediğimize göre seçmeliyiz. Daha fazla bağımlılık sorgulamak otomatik olarak daha iyi health check yazmak değil; yanlış tepkiyi daha sık tetiklemek de olabilir.

Bir kontrolün başarısızlığını yeniden başlatmaya bağlamak ciddi bir geri bildirim döngüsü oluşturur. Geçici dış servis kesintisi bütün instance’ları aynı anda yeniden başlatırsa toparlanma daha zor hale gelebilir. Bu yüzden dış bağımlılıkları liveness’a otomatik eklememek iyi bir başlangıçtır. Yine de bütün sistemler için tek kural yok; uygulamanın nasıl toparlandığı ve orchestrator’ın ne yaptığı anlaşılmalı. Tepki, tespit edilen durumu gerçekten düzeltebilecek nitelikte olmalı.

İki endpoint’i ayrı kontrollerle kurmak

Önce basit process kontrolünü ve veritabanı kontrolünü farklı tag’lerle kaydedelim:

builder.Services.AddHealthChecks()
    .AddCheck(
        "process",
        () => HealthCheckResult.Healthy(),
        tags: ["live"])
    .AddCheck<DatabaseReadyCheck>(
        "database",
        failureStatus: HealthStatus.Unhealthy,
        tags: ["ready"],
        timeout: TimeSpan.FromSeconds(2));

Sonra endpoint’lerin hangi kayıtları çalıştıracağını açıkça seçebiliriz:

app.MapHealthChecks("/health/live", new HealthCheckOptions
{
    Predicate = registration => registration.Tags.Contains("live")
});

app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
    Predicate = registration => registration.Tags.Contains("ready")
});

Microsoft.Extensions.Diagnostics.HealthChecks ve Microsoft.AspNetCore.Diagnostics.HealthChecks namespace’leri gerekir. Burada tag isimleri uygulamanın kendi seçimidir. Bütün kontrolleri iki endpoint’e de ekleyip yalnızca adresleri farklı yapmak aynı ayrımı sağlamaz. Predicate’in gerçekten farklı kayıtları seçtiği test edilmelidir. Configuration’da bir kontrolün tag’i değiştiğinde endpoint davranışı da değişebilir; bu küçük alanlar operasyonel anlam taşır.

Ready grubunda tek kayıt var; predicate yanlış tag seçerse bu kontrol hiç çalışmayabilir. Endpoint yine başarılı görünüyorsa yalnız 200 bekleyen test bunu yakalayamaz. Veritabanı kontrolünü testte kontrollü biçimde başarısız yapıp readiness’ın sonucunun değiştiğini görmeliyiz. Böylece hem kaydı hem endpoint’in onu seçtiğini denemiş oluruz. Tag adındaki küçük bir değişiklik gerçek trafik kararını etkilediği için bu bağlantıyı açık tutmak yararlı.

Veritabanına bağlanabilmek hangi güvenceyi veriyor?

Basit bir readiness kontrolü bağlantı kurulabildiğini denetleyebilir. DbContextFactory kullanarak kısa bir kapsam oluşturalım:

public sealed class DatabaseReadyCheck(
    IDbContextFactory<HealthDbContext> factory)
    : IHealthCheck
{
    public async Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default)
    {
        await using var db = await factory.CreateDbContextAsync(
            cancellationToken);

        var connected = await db.Database.CanConnectAsync(
            cancellationToken);

        return connected
            ? HealthCheckResult.Healthy()
            : HealthCheckResult.Unhealthy("Database unavailable.");
    }
}

HealthDbContext normal bir DbContext sınıfıdır ve AddDbContextFactory kaydı gerçek bağlantı bilgisiyle yapılmalıdır. Bu kontrolün sınırı özellikle dar: bağlantı kurulabildiğini deniyor. Şemanın doğru olduğunu, migration’ların tamamlandığını, gerekli tablolara yazılabildiğini veya cihaz iş akışının uçtan uca başarılı olduğunu kanıtlamıyor. Health endpoint’ini bir üretim fonksiyon testi gibi okumamak gerekir. Daha güçlü kontrol gerekiyorsa hangi işlem gerektiği açıkça seçilmelidir.

Kontrol içinde gerçek veri değiştirmek de dikkat ister. Her probe çağrısında audit satırı eklemek veya cihaz komutu göndermek bir sağlık denemesini yan etkili iş akışına çevirir. Böyle bir kontrol özel ihtiyaçta tasarlanabilir; fakat varsayılan bir bağlantı kontrolü gibi gizlenmemeli. Tekrar sayısı ve başarısızlık davranışı düşünülmeli. Probe trafiğinin kendisi üretim verisini gereksiz değiştirmemeli.

İki saniyelik timeout her şeyi iki saniyede bitirmiyor

Health check kaydındaki timeout bir zaman bütçesi tanımlar; kontrolün cancellation token’ını gerçekten gözlemesi gerekir. Alt katman iptali işlemiyorsa bütün maliyet sihirli biçimde ortadan kalkmaz. Bu nedenle token’ı context oluşturma ve bağlantı denemesine taşıdık. Bunun yanında provider’ın bağlantı süresi ve ilgili ağ davranışları da etkili olabilir. Timeout ayarını yazmak ile gerçek kesinti davranışını denemek farklı adımlardır.

Probe’ların çok sık çalışması da yük oluşturabilir. Her instance her saniye birden fazla bağlantı testi yapıyorsa, sistem sorun yaşarken ek bağlantı baskısı doğabilir. Kontrolün sıklığı, timeout’u ve başarısızlık eşiği birlikte düşünülmeli. Burada ideal probe aralığı vermiyoruz; uygulamanın toparlanma süresi ve operasyon beklentisi ölçülmeli. Bir sağlık kontrolü, bağımlılığın üzerindeki en saldırgan istemciye dönüşmemeli.

Bazı durumlarda yakın zamandaki kontrol sonucu kısa süre saklanabilir. Bu, kontrol maliyetini azaltırken geçici bir güncellik gecikmesi getirir. Aynı sonucu ne kadar süre kullanacağımız, readiness kararının ne kadar hızlı değişmesi gerektiğine bağlıdır. Cache eklenmiş kontrolü anlık durum kanıtı gibi anlatmamak gerekir. Her optimizasyonun gözlem anlamına etkisi vardır. Sonucun hangi zamanda üretildiğini bilmek bu nedenle yararlı olabilir.

Her dış servis readiness’ı düşürmeli mi?

Cihaz komutu için zorunlu veritabanı ile isteğe bağlı raporlama entegrasyonu aynı kritik düzeyde olmayabilir. İsteğe bağlı servis geçici kapalıyken bütün API trafiğini durdurmak ürün için gereksiz bir kesinti yaratabilir. Diğer taraftan zorunlu bağımlılık olmadan başarılı yanıt veriyormuş gibi yapmak da yanlış olabilir. Readiness kapsamı, uygulamanın gerçekten hangi işleri kabul edebildiğine göre seçilmeli. Bağımlılık sayısı kadar kontrol eklemek tek başına doğru tasarım değildir.

Çok amaçlı bir API’de tek global readiness sonucu bazı ayrıntıları kaybedebilir. Farklı trafik yollarını ayırmak veya kısmi kullanılabilirlik modeli kurmak gerekebilir. Ancak küçük bir uygulamada bu ayrımı baştan aşırı büyütmek de gereksizdir. Önce hangi bağımlılığın bütün yeni işleri engellediği belirlenebilir. Gerçek ihtiyaç ortaya çıktığında endpoint veya trafik sınırı ayrıştırılır. Sağlık modeli, uygulamanın ürün sınırlarını takip etmeli.

Degraded durumunun HTTP sonucuyla ilişkisi de açık olmalı. Bir kontrol Degraded döndürdüğünde onu tüketen load balancer’ın ne yapacağı varsayılmamalı. ASP.NET Core result mapping’i ve altyapının beklediği kodlar birlikte incelenir. Yalnızca renkli bir dashboard’da sarı görmek trafik kararını anlatmaz. Aynı health sonucu farklı tüketicilerde farklı davranışlara bağlanabilir; bu bağlantı deployment tanımının parçasıdır.

Başlangıç ve kapanış sırasında

Uygulama HTTP yanıtı vermeye başlamış olsa bile başlangıçtaki zorunlu hazırlığı tamamlanmamış olabilir. Örneğin gerekli configuration yükleniyor veya özel bir cache hazırlanıyordur. Bu iş tamamlanmadan readiness’ın başarılı olması istenmeyebilir. Buna karşılık uzun hazırlık süresini liveness hatası sayıp sürekli yeniden başlatmak hazırlığın hiç bitmemesine neden olabilir. Başlangıç davranışı ayrı bir durum olarak ele alınmalı.

Kapanışta da yeni iş kabulünü durdurmak ile devam eden işlerin bitmesini beklemek aynı anda gerçekleşmeyebilir. Readiness’ın düşmesi yeni trafiği yönlendirmeye yardımcı olabilir; ancak ağdaki ve load balancer’daki yayılma gecikmesi nedeniyle sıfır yeni istek garantisi çıkarılmamalı. Uygulamanın graceful shutdown süresi ve işlem iptali ayrıca yönetilmeli. Health endpoint’i, bütün kapanış protokolünün yerine geçmez. Sadece bu protokole bilgi sağlayan bir parçadır.

Bir worker uygulamasında da HTTP process kontrolü yeterli olmayabilir. Kritik tüketici döngüsü durmuş ama sağlık endpoint’i çalışıyor olabilir. Böyle bir uygulamada son başarılı ilerleme zamanı veya işleyici durumu gibi bir sinyal anlamlı hale gelebilir. Bunun da kuyruk boş olduğu için iş yapılmayan durumla karıştırılmaması gerekir. İlerleme yok, iş yok ve işleyici çalışmıyor farklı gözlemlerdir. Kontrolün neyi ayırt ettiği açıkça yazılmalı.

Sağlık yanıtında ayrıntı paylaşmak

Public bir health endpoint’inde connection string, sunucu adı veya ham exception içeriği döndürmek gerekmeyebilir. Basit durum yanıtı trafik kararı için yeterli olabilir. Ayrıntılı tanılama gerekiyorsa erişimi daha dar bir izleme yolu kullanılabilir. JSON response yazıcısı eklendiğinde bütün HealthReport nesnesini düşünmeden serialize etmek bu sınırı büyütebilir. Hangi alanın hangi tüketiciye gerektiği seçilmeli.

Authentication eklenmesi de altyapıyla uyumlu olmalı. Probe kimlik doğrulayabiliyor mu, endpoint’e ağ erişimi nasıl sınırlandırılıyor, başarısız auth ile gerçek health hatası nasıl ayrılıyor? Bunlar deployment’ın somut özellikleridir. Güvenlik gerekçesiyle endpoint’i kapatıp sonra load balancer’ın onu okuyamadığını fark etmek de bir kurulum hatasıdır. Erişim modeli ile operasyonel tüketim birlikte doğrulanmalıdır.

Davranışı gerçek başarısızlıkla test etmek

İlk testte live ve ready endpoint’leri başarılı olabilir. Sonra yalnızca veritabanı kontrolü kontrollü biçimde başarısız yapılır. Beklentimiz readiness’ın başarısız olurken liveness’ın çalışmaya devam etmesidir. Böylece yalnızca tag listesini okumayız; kayıtların gerçekten farklı sonuçlar ürettiğini görürüz. Sonraki adım altyapının bu sonuçlara hangi tepkiyi verdiğini denemektir. Uygulama testi, orchestrator yapılandırmasını tek başına kanıtlamaz.

Timeout, boş tag seçimi ve kontrolün exception üretmesi ayrı senaryolar olabilir. Bir endpoint’in her koşulda 200 vermesi sağlıklı olduğu kadar, yanlış yapılandırıldığı anlamına da gelebilir. Testte başarısızlık üretemiyorsak kontrolün gerçekten çalıştığını bilmiyor olabiliriz. Kontrollü bir sahte bağımlılık, framework bağlantısını sınamak için yeterlidir; gerçek veritabanı kesintisi davranışı ise uygun entegrasyon ortamında ayrıca denenir.

Health check bir izleme stratejisinin tamamı değil

CPU, hata oranı, kuyruk yaşı, kullanıcı gecikmesi ve iş sonuçları health endpoint’inden ayrı gözlemler olabilir. Hepsini tek bir 200 veya 503 sonucuna sığdırmak mümkün değildir. Readiness başarılıyken belirli bir endpoint’in yavaşlaması normal bir olasılıktır. Bu, health check’in gereksiz olduğu anlamına gelmez; kapsamının sınırlı olduğunu gösterir. Operasyonel kararların hangi kanıta dayanacağı ayrı ayrı belirlenmeli.

İlk sürümde iki soruyu ayrı sormak yeterli olabilir: process yanıt veriyor mu ve yeni iş almak için gereken koşullar hazır mı? Sonra bu yanıtları okuyan load balancer veya orchestrator’ın beklenen davranışı gösterdiğini kontrol ederiz. Uygulama endpoint’inin doğru status dönmesi, altyapı bağlantısının da kurulduğunu söylemez. Trafiğin gerçekten kesildiğini ve bağımlılık toparlanınca yeniden açıldığını görmek tasarımın diğer yarısıdır.

Her instance aynı veritabanı arızasını görürse

Sağlık endpoint’ine ulaşan ağ yolunu da kontrol etmek gerekir. Uygulama kendi içinden bağımlılığa bağlanabilirken dış probe yanlış port veya path nedeniyle başarısız olabilir. Bu durum uygulamanın hazır olmadığını değil, kontrolün yanlış yere gittiğini gösterebilir. Teşhiste status kodu, hedef adres ve uygulama logunda gerçekten çağrı görülmesi birlikte incelenir. Varsayılan olarak bütün bileşenleri yeniden başlatmak kanıt üretmez ve ilk arızanın izini kaybettirebilir.

Deployment sırasında eski ve yeni sürüm aynı anda trafik alıyorsa readiness’in şema değişikliğiyle ilişkisi önem kazanır. Yeni sürümün bağlantı kurabilmesi eski sürümün aynı veritabanıyla çalışabildiğini göstermez. Sağlık kontrolüne migration çalıştırma sorumluluğu yüklemek yerine dağıtımın uyumluluk planı ayrıca yapılmalıdır. Probe yalnızca durum okumalı; her çağrıda şemayı değiştiren bir komuta dönüşmemelidir. Böylece kontrolün yan etkisi ve tekrar davranışı sade kalır.

Sonuçları kaydederken instance kimliği ve sürüm bilgisi faydalı olabilir; ancak bunları herkese açık yanıt gövdesine koymak zorunlu değildir. Kontrollü log veya metrik etiketleri yeterli olabilir. Hangi sürümün hazır olamadığını bilmek, aynı sorunun bütün sisteme mi yoksa tek dağıtıma mı ait olduğunu ayırmayı kolaylaştırır. Yine de yüksek çeşitlilikte etiket üretmenin izleme maliyeti düşünülmeli; her request için yeni sağlık kimliği oluşturulmamalıdır.

Veritabanı kısa süre erişilemez olduğunda bütün uygulama instance’larını yeniden başlatmak genellikle bağlantıyı geri getirmez. Aksine yeniden açılan süreçlerin aynı anda bağlantı kurmaya çalışması toparlanmayı zorlaştırabilir. Bu yüzden dış bağımlılık hatasını doğrudan liveness başarısızlığına bağlamıyoruz. Readiness trafiği durdurabilir; liveness ise uygulamanın kendi çalışabilirliğine ilişkin daha dar bir soruya cevap vermelidir. Kontrolün sonucu ile altyapının uyguladığı tepki aynı tasarım içinde düşünülmelidir.

Bütün instance’ların hazır değil olması da kullanıcıya hizmet verilemeyeceği anlamına gelebilir. Bu istenen davranış olabilir; ancak yük dengeleyicinin o durumda nasıl yanıt verdiği bilinmeli. Bazı endpoint’ler veritabanı olmadan çalışabiliyorsa bütün uygulamayı tek readiness koşuluyla çıkarmak gereğinden geniş bir etki yaratabilir. Ayrı servis sınırı veya uygulama içinde kontrollü kısmi hizmet seçenekleri değerlendirilebilir. Her bağımlılık için aynı kararı otomatik vermek yerine ürünün kullanılabilirlik beklentisi esas alınmalıdır.

Bir bağımlılığın opsiyonel olması, hatasının görünmez bırakılacağı anlamına gelmez. Örneğin bildirim sağlayıcısı çalışmıyorken ana API hizmet verebilir. Readiness sağlıklı kalırken ayrı metrik veya alarm bildirim sorununu gösterebilir. Sağlık endpoint’ini bütün izleme ihtiyaçlarını taşıyan tek bir rapora çevirmemek burada yararlıdır. Trafik kabulü kararı ile operasyon ekibinin arızayı görmesi farklı kanallar üzerinden yönetilebilir.

Probe sıklığı küçük bir ayrıntı değil

Bir sağlık sorgusu hafif olsa bile çok sayıda instance tarafından sık çağrıldığında toplam yük oluşturur. Her çağrıda bağlantı açıp kapsamlı tablo sorgusu yapmak özellikle sorun anında ek baskı yaratabilir. Kontrol, trafik kararı için gereken en küçük işi yapmalıdır. Veritabanındaki bütün tabloları saymak veya gerçek bir iş komutu çalıştırmak sağlık denetimini başka bir iş yüküne dönüştürür. Ölçümün kendisinin sistemi zorlamaması gerekir.

Aralık ve başarısızlık eşiği birlikte düşünülmeli. Tek gecikmiş yanıtı arıza saymak kararsız trafik giriş çıkışına neden olabilir. Çok yüksek eşik ise gerçekten bozuk instance’ın uzun süre trafik almasını sağlayabilir. Doğru değer için uygulamanın normal başlangıç süresi, kısa süreli gecikmeleri ve kabul edilen kesinti süresi bilinmelidir. Bu yazı bütün sistemlere aynı saniye değerini önermiyor. Altyapı ayarları gerçek davranışla denenmelidir.

Kontrol sonucunu önbelleğe almak maliyeti azaltabilir; fakat arızanın veya toparlanmanın görünmesini geciktirir. Bu bir trade-off’tur ve açık seçilmelidir. Aynı anda gelen probe çağrılarının tek bir denetimi paylaşması düşünülebilir; ancak küçük uygulamada böyle bir koordinasyon gerekmeyebilir. Önce sağlık denetiminin gerçekten maliyetli olduğuna ilişkin ölçüm gerekir. Basit bağlantı kontrolünü gereksiz bir durum makinesine çevirmek bakım yükünü artırabilir.

Uygulama açıldı ama henüz hazır değil

Başlangıçta model yükleme, önbellek hazırlama veya başka bir hazırlık işi bulunabilir. HTTP sunucusunun dinlemeye başlaması bu işin bittiğini göstermeyebilir. Readiness’e hazırlık durumunu yansıtan kontrollü bir sinyal eklemek mümkündür. Ancak bu sinyalin ne zaman başarıya geçtiği ve hata halinde ne yaptığı açık olmalı. Arka plan task’ı exception ile bitmişken boolean alanın yanlışlıkla true kalması, sağlık endpoint’inin gerçek durumu saklamasına neden olabilir.

Kubernetes startup probe kullanılıyorsa bunun liveness ve readiness ile etkileşimi ilgili sürüm belgelerinden okunmalıdır. Uzun başlangıcı liveness eşiklerini çok büyüterek çözmek, çalışma sırasında gerçek takılmayı fark etme süresini de uzatabilir. Başlangıç ile normal çalışma farklı davranışlar olduğundan ayrı probe amacı yararlı olabilir. Yine de yalnızca Kubernetes’te örnek var diye her dağıtıma aynı konfigürasyonu taşımak gerekmez; kullanılan platformun gerçek mekanizması esas alınır.

Kapanışta da benzer bir geçiş vardır. Instance artık yeni trafik almamalı, fakat eldeki istekleri uygun süre içinde tamamlamalı olabilir. Readiness’in düşmesi, yük dengeleyicinin bunu görmesi ve açık bağlantıların bitmesi aynı anda gerçekleşmez. Uygulamanın graceful shutdown süresi bu akışla uyumlu olmalıdır. Sadece health yanıtını değiştirip bütün isteklerin güvenle boşaltıldığını varsaymak yeterli değildir. Gerçek dağıtım yolunda kapanış testi yapılmalıdır.

Kontrol sonucu ile timeout bütçesi

Health check kaydında verilen timeout, alt bağımlılığın her koşulda tam o sürede fiziksel olarak duracağını garanti etmez. Alt çağrının cancellation desteği ve kendi bağlantı timeout’u önem taşır. Kontrolün çağırdığı kütüphane iptali dikkate almıyorsa bekleyen işler birikebilir. Bu nedenle testte yalnızca endpoint’in status kodunu görmek yetmez; arka planda kalan denetimlerin ve kaynakların davranışı da gözlenmelidir.

Timeout süresi normal iş isteğinden çok kısa seçilirse sağlık denetimi hizmet verebilen instance’ı gereksiz yere çıkarabilir. Çok uzun seçilirse karar gecikir ve probe çağrıları üst üste binebilir. Bu denge için bağımlılığın normal gecikme dağılımı ve platformun beklentisi gerekir. Tek bir yerel bağlantı süresi üretim eşiğini belirlemek için yeterli değildir. Kontrollü gecikme eklenen testler, kararın sınırlarını daha görünür hale getirir.

Sağlık endpoint’inin bilgi sınırı

Dışarıya dönen ayrıntılı hata mesajında sunucu adı, connection string veya exception içeriği bulunabilir. Trafiği yöneten sistemin çoğu zaman yalnızca sağlıklı veya hazır değil sonucuna ihtiyacı vardır. Ayrıntılar kontrollü operasyon kanalına bırakılabilir. Endpoint’in kimler tarafından erişilebilir olduğu ağ ve kimlik doğrulama tasarımına bağlıdır. Güvenlik eklemek probe’un erişimini engelliyorsa bu durum testte yakalanmalı; çözüm olarak bütün bilgileri herkese açmak tercih edilmemelidir.

Yanıtın cache edilmesi de gözden kaçabilir. Aracı katman eski sağlıklı yanıtı döndürüyorsa uygulamanın gerçek başarısızlığı gizlenebilir. Platformun probe isteğinin gerçekten uygulamaya ulaştığı ve uygun cache davranışının korunduğu doğrulanmalıdır. Bu, endpoint kodunun tek başına göremediği bir dağıtım ayrıntısıdır. Sağlık tasarımını uygulama metodu ve altyapı ayarları birlikte oluşturur.

Başarısızlığın geri dönüşünü de sınamak

Testte önce bağımlılığı başarısız yapıp readiness’ın düştüğünü görebiliriz. Ardından bağımlılığı geri getirip instance’ın tekrar hazır olduğunu da kontrol edelim. İlk hatadan sonra kalıcı olarak bozuk state’te kalıyorsa yalnız red yolunu denemiş olmak yeterli değil. Bu sırada liveness’ın seçtiğimiz sonucu koruduğuna da bakarız. Böylece arıza ve toparlanmada trafik kararıyla process’i yeniden başlatma kararının birbirine karışmadığını aynı senaryoda izleyebiliriz.

CanConnectAsync kontrolü gerçek şema uyumluluğunu veya bütün iş sorgularının başarısını kanıtlamaz. Yetkisi yetersiz bir kullanıcı bağlantı kurabilir, gereken tablo bulunmayabilir veya bir sorgu kilitlenebilir. Sağlık denetiminin verdiği güvence bu sınırla ifade edilmelidir. Daha geniş iş doğrulaması gerekiyorsa kontrollü sentetik işlem veya ayrı izleme düşünülebilir. Her istekte kapsamlı iş çalıştırmak yerine hangi arızayı hangi sinyalin göstereceğini açıkça eşleştirmek daha kullanışlıdır.

Başlangıç yapılandırmasının bağlamı için Dependency Injection yazısı okunabilir. API ve tag seçimi Microsoft Health Checks belgesinde, process ve trafik ayrımı Kubernetes probe kavramlarında ele alınıyor. Buradaki kod herhangi bir Kubernetes kurulumunun hazır olduğunu varsaymıyor.

By tanju.bozok

Senior .NET Engineer | Backend architecture, distributed systems & real-time communication