Feign Client — Kolaylığın Gizlediği Şeyler
Önce şunu oku: BFF — Backend for Frontend
30 saniyede özet
Feign, başka bir servise yapılan HTTP çağrısını sıradan bir metot çağrısı gibi gösterir. Kolaylık gerçek, ama görünmeyen üç şey var: gecikme, yarım kalan hatalar ve çoğu zaman yanlış gelen varsayılan ayarlar.
Başka bir servisi çağırmak normalde otuz satır tekrar eden kod ister. Feign ile yalnızca bir arayüz yazarsın, çağrıyı yapan kodu Spring üretir. RestTemplate ile yazacağın otuz satırlık tekrar kaybolur.
-
Bayt: Feign ile başka bir servisi çağırmak tek satır: priceClient.getPrice(id). Otuz satır gitti!
-
Sen: Harika, yerel bir metot gibi.
-
Bayt: Ama fiyat servisi yavaşlayınca bizim servis de kilitlendi...
-
Bayt: Sekretere şunu sor demek kolay. Hat kopunca ne olacağını da bilmek gerekiyor.
Feign ne verir, ne vermez?
@FeignClient(name = "pricing")interface PricingClient { @GetMapping("/prices/{id}") Price get(@PathVariable String id);}Gövde yazmazsın; Spring bu arayüzün uygulamasını üretir ve bean olarak verir. Kazanç tekrarın silinmesi: URL kurma, serileştirme, yanıt okuma tek yerde.
Vermediği şeyler de aynı ölçüde net: timeout, retry politikası, hata çevirimi, devre kesici. Bunların hiçbiri Feign’i eklemekle gelmez — hepsi ayrı ve açık kararlardır.
Kafam karıştı, daha basit anlat
Feign, başka bir servisi aramayı bir arayüz yazmak kadar kolaylaştırır. Adresi kurmak, isteği göndermek, cevabı okumak senin yerine yapılır.
Feign client ne yapar?
Feign ile `WebClient` arasındaki temel fark nedir?
Yerel çağrı gibi görünür, değildir
pricing.get(id) satırına bak. Bir List.get(id) çağrısından hiçbir farkı yok.
Oysa arkasında servis keşfi, bağlantı kurma, ağ üzerinden istek, serileştirme ve karşı tarafın yükü var. İmza bunların hiçbirini söylemiyor — ve söylemediği için kod incelemesinde kimse sormuyor.
Kafam karıştı, daha basit anlat
Satır yan odaya seslenmek gibi görünür, ama aslında başka şehri telefonla aramaktır. Hat meşgul olabilir, geç cevap gelebilir. Kod bunu sana söylemez, sen hatırlamalısın.
Feign'in kolaylığının getirdiği asıl risk nedir?
Satır satır: aynı arayüz, üç sürpriz
Fiyat servisi bu id için 404 dönerse, senin API'n çağırana ne döner? Cevabı göster
Varsayılan hâlde 500. FeignException.NotFound bir RuntimeException’dır ve hiçbir yerde yakalanmazsa controller’dan dışarı sızar — çağıran “sunucu hatası” görür, oysa gerçek “bulunamadı”.
Adım adım oku
- priceClient.getPrice(id) kodda sıradan bir metot çağrısı gibi durur.
- Arkasında ise ağ üzerinden giden bir HTTP isteği, yani bir telefon hattı vardır.
- Hat takılabilir, karşı taraf meşgul çalabilir ya da bulunamadı diyebilir.
- Zaman aşımını, yalnızca güvenli çağrılar için yeniden denemeyi ve hataların doğru çevrilmesini sen ayarlarsın.
Varsayılanlarla ne oluyor?
@FeignClient(name = "pricing")interface PricingClient { @GetMapping("/prices/{id}") Price get(@PathVariable String id);} @GetMapping("/products/{id}")ProductDto product(@PathVariable String id) { return new ProductDto(catalogue.find(id), pricing.get(id));}Debug
üretim Spring başlangıçta bu arayüzün uygulamasını üretir. Yazmadığın kod, hata ayıklarken de göremediğin kod.
- yazdığın satır
- = 1
- çalışan katman
- = keşif + HTTP + serileştirme
Sol/sağ ok tuşlarıyla da gezebilirsin.
Son adım en kritik olanı: retry katmanlar boyunca toplanmaz, çarpılır. Zorlanan bir servise en çok yüklenen taraf, onu kurtarmaya çalışan çağıran olur.
Üst servis 404 dönüyor ve senin API'n de 404 dönsün istiyorsun. Ne yaparsın?
Her davranışı, Feign'i eklemekle geldiğine mi yoksa açıkça yapılandırman gerektiğine göre ayır.
Kendin gör
Fiyat servisinin davranışını, metodu, timeout’ları, retry’ı ve dismiss404’ü değiştir. Üstte ayarların kod hâli, altta her denemenin thread’i ne kadar tuttuğu var.
Feign çağrısı — varsayılan ayarlar neye mal oluyor?
Tohum 856798@FeignClient(name = "pricing", configuration = PricingClientConfig.class)interface PricingClient { @GetMapping("/prices/{id}") Optional<Price> get(@PathVariable String id);} class PricingClientConfig { @Bean Request.Options options() { return new Request.Options(10000, MILLISECONDS, 60000, MILLISECONDS, true); } @Bean Retryer retryer() { return Retryer.NEVER_RETRY; }}Oynat veya adımla: pricing çağrısı başlayacak.
Şu an ne oldu?
GET çağrısı başlıyor
Kod tek satır: pricing.get(id). Adımla ve bu tek satırın thread'i ne kadar tuttuğunu gör.
Görevler0/4
Tek bir isteğin bir thread'i en az 60 saniye tutmasını sağlaaçık
İpucu
Varsayılan ayarlarla yavaş servisi çağır. Read timeout'u değiştirme.
Yavaş servise karşı 3 saniye içinde hata dönaçık
İpucu
Read timeout'u düşür ve retry'ı kapalı tut. Hızlı başarısızlık, yavaş başarısızlıktan iyidir.
404'ü istisna değil Optional.empty() olarak alaçık
İpucu
Servisi "Bu id için 404" yap. Hangi ayar 404'ü boş bir değere çevirir?
Retry ile aynı POST'tan birden fazla rezervasyon oluşturaçık
İpucu
POST seç, Retryer.Default'u aç ve yavaş servisi kısa bir read timeout ile çağır.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanlarla oynat. Fiyat servisi yavaş, retry yok. Tek satırlık
pricing.get(id)bir thread’i tam 60 saniye tutuyor ve sonunda istisna atıyor. Retryer.Default’u aç. Beş deneme ve aralarındaki beklemeler: aynı çağrı artık beş dakikadan uzun sürüyor. Spring Cloud OpenFeign’ın retry’ı varsayılan olarak kapatmasının sebebi bu.- Read timeout’u 2 saniyeye indir, retry’ı kapat. Çağrı iki saniyede başarısız oluyor. fail fastBaşarısız olacağı belli olan bir işlemi beklemeden reddetmek. Breaker açıkken çağrının ağa hiç çıkmaması budur — çağıranın thread'i timeout boyunca tutulmaz.Sözlükte gör →, yavaş başarısızlıktan iyidir.
- POST seç ve retry’ı yeniden aç. Yavaş sunucu vazgeçilen her isteği yine de işliyor: tek bir rezervasyon isteği beş kayıt bırakıyor.
- Servisi 404’e çevir. Retry açık olsa da tek deneme yapılıyor, çünkü 404 bir ağ hatası değil.
dismiss404ile istisna yerineOptional.empty()dönüyor.
Kafam karıştı, daha basit anlat
Simülatörde bir çağrının thread’i ne kadar tuttuğuna bak. Timeout yoksa, yavaş bir servis senin thread’lerini de yavaş yavaş tüketir.
Simülatörde fiyat servisi yavaş, read timeout varsayılan 60 sn ve Retryer.Default açık. Tek bir GET çağrısı thread'i ne kadar tutar?
Tuzaklar
Sessiz fallback. Devre kesici fallback’i boş liste döndürüyorsa kullanıcı hatasız ama yanlış bir sayfa görür ve kimse alarm almaz. Fallback bir gizleme aracı değil, bilinçli bir azaltılmış hizmet kararıdır — ve her zaman metriğe yazılmalıdır.
Retry’ı idempotent olmayan çağrıya koymak. POST /orders timeout aldığında siparişin oluşup oluşmadığını bilemezsin. idempotencyAynı işlemin bir kez de on kez de çalışsa aynı sonucu vermesi. Dağıtık sistemde timeout aldığında işlemin yapılıp yapılmadığını bilemediğin için zorunludur.Sözlükte gör → anahtarı yoksa retry, ikinci bir sipariş demektir.
Sağlayıcının yayınladığı ortak client kütüphanesi kolay görünür: fiyat ekibi PricingClient’ı paketleyip yayınlar. Bedeli, tüketicilerin sağlayıcının sürüm takvimine bağlanması ve arayüzün sağlayıcının modeline göre şekillenmesidir. Arayüzü tüketici tanımlarsa bağımlılık oku doğru yöne bakar.
Timeout bütçesini hesaba katmamak. timeout bütçesiBir zincirdeki timeout değerlerinin içten dışa artacak şekilde bölünmesi. Dıştaki içtekinden küçükse çağıran vazgeçer ama iş devam eder.Sözlükte gör → aşağı indikçe küçülmeli ve retry’lı toplam süre dıştaki bütçeyi aşmamalı. Aşarsa çağıran vazgeçer, senin çağrın devam eder.
Aşağıdaki örnek bir bankanın transfer servisinden; hesap servisine Feign ile soruyor. Feign’in vermediği dört şey açıkça ekleniyor: istemci başına zaman aşımı, bilinçli retry kararı, hata çevirimi ve Feign’i domain’den saklayan bir adaptör. Test gerçek HTTP’yi WireMock ile taklit ediyor.
Derinleş · Hesap servisi istemcisi: Feign'in etrafında ne var? 6 dosya · ~87 satır · ilk okumada atlayabilirsin
Kendini sına
Feign çağrısı arka planda bir HTTP isteğidir.
Fiyat servisi bu id için 404 dönüyor. Senin API'n çağırana ne döner?
Aklında kalacak üç şey
- 1 Feign'in tek işi tekrarı silmektir: arayüzü sen yazarsın, çağrıyı yapan kodu Spring üretir. Sağlamlıkla ilgili hiçbir şey getirmez.
- 2 Asıl risk görünüşte: pricing.get(id) yerel bir çağrıya benzediği için gecikme, zaman aşımı ve hata ihtimali gözden kaçar.
- 3 Tekrar denemeler katmanlar boyunca çarpılır. Feign, yük dengeleyici ve resilience4j ayrı ayrı denerse tek bir istek düzinelerce isteğe dönüşür.
5 kart sonraki derste seni bekliyor
Bu dersin üstüne kurulanlar
Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.