← Back to list

Java ile Microservis Yolculuğu — 5: Sistem Çökmesin!

Serinin 4. yazısında, garsonumuzun (Order Service) siparişi almadan önce mutfağı (Customer Service) arayıp “Böyle bir müşteri var mı?” diye…

Alper Bilğin · 2026-02-10 07:46 · 9 claps · 3.8 min read
#java #spring-boot #resilience4j #circuit-breaker #microservices
Open on Medium ↗
Wiki topics: 🚀 · Self Improvement 🛠️ · Crafts & DIY

Java ile Microservis Yolculuğu — 5: Sistem Çökmesin! Resilience4j ve Circuit Breaker (Sigorta) Mekanizması

Serinin 4. yazısında, garsonumuzun (Order Service) siparişi almadan önce mutfağı (Customer Service) arayıp “Böyle bir müşteri var mı?” diye sormasını sağlamıştık. Her şey mükemmel çalışıyordu… Taki mutfaktaki o telefon cevap vermeyene kadar.

Microservis mimarisinde en büyük kabus “Domino Etkisi”dir (Cascading Failure). Restoran analojimizden düşünelim: Garson (Order Service), mutfağı (Customer Service) arıyor. Mutfak cevap vermiyor (Servis çökmüş veya çok yavaş). Garson elinde telefonla bekliyor. O sırada ikinci bir müşteri geliyor, garson yine arıyor, yine bekliyor. Bir süre sonra tüm garsonlar ellerinde telefonla donup kalır. Kimse sipariş alamaz hale gelir. Sadece mutfak değil, restoranın tamamı (Order Service dahil) kilitlenir.

İşte bu durumu engellemek için evlerimizdeki elektrik sigortasına benzeyen bir yapı kullanacağız: Circuit Breaker (Devre Kesici).

Bu yazıda, endüstri standardı olan Resilience4j kütüphanesini kullanarak sistemimize “Sigorta” takacağız.

Sigorta Mantığı (Circuit Breaker) Nedir?

Resilience4j, servisimizdeki hata oranını sürekli izler ve duruma göre 3 farklı moda geçer:

1.CLOSED (Kapalı — Her Şey Yolunda):

  • Akım geçiyor. Garson mutfağı arıyor, cevap alıyor.
  • İşleyiş normal.

2.OPEN (Açık — Sigorta Attı):

  • Hata oranı belirlenen eşiği (örneğin %50) geçerse sigorta atar.
  • Garson artık mutfağı ARAMAZ. Telefonu kaldırmadan doğrudan müşteriye döner ve “Mutfak şu an yanıt veremiyor, işleminizi sonra yapalım” der (Fail Fast). Böylece garson boşa beklemez.

3.HALF-OPEN (Yarı Açık — Test Modu):

  • Sigorta attıktan belli bir süre sonra (örneğin 10 saniye), sistem “Acaba mutfak düzeldi mi?” diye 1–2 deneme isteği gönderir. Başarılıysa sigortayı kapatır (Normale döner), başarısızsa tekrar açar.

1. Adım: Bağımlılıkları Eklemek

Sigortayı takmak istediğimiz servise, yani arayan tarafa (Order Service) müdahale edeceğiz. order-service projesinin pom.xml dosyasına şu iki bağımlılığı ekleyin:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Ekledikten sonra Maven projesini yenilemeyi/Reload yapmayı unutmayın.

2. Adım: Sigorta Ayarları (Konfigürasyon)

Sigortanın ne zaman atacağını application.properties dosyasında belirleyeceğiz. order-service ayar dosyasına şunları ekleyin:

# --- Resilience4j Circuit Breaker Ayarları ---

# "customerService" adında bir sigorta tanımlıyoruz
resilience4j.circuitbreaker.instances.customerService.registerHealthIndicator=true

# Son 5 isteğe bakarak karar ver (Sliding Window)
resilience4j.circuitbreaker.instances.customerService.slidingWindowSize=5

# Eğer bu 5 isteğin %50'si (yani 3 tanesi) hata verirse sigortayı attır
resilience4j.circuitbreaker.instances.customerService.failureRateThreshold=50

# Sigorta attığında (OPEN state), 10 saniye bekle, sonra tekrar dene (HALF-OPEN)
resilience4j.circuitbreaker.instances.customerService.waitDurationInOpenState=10000

# Yarı açık modda kaç deneme isteğine izin verilsin?
resilience4j.circuitbreaker.instances.customerService.permittedNumberOfCallsInHalfOpenState=3

# --- Time Limiter (Zaman Aşımı) Ayarları ---
# Garson en fazla 2 saniye telefonda beklesin. Cevap yoksa kapatsın.
resilience4j.timelimiter.instances.customerService.timeoutDuration=2s

3. Adım: Fallback (B Planı) Yazmak

Şimdi kodun içine girip, “Sigorta atarsa ne yapayım?” sorusuna cevap vereceğiz.

Önemli Sürüm Notu: Spring Boot 2.4 ve Spring Cloud 2020 sonrası sürümlerde, ana sınıfa @EnableCircuitBreaker anotasyonu eklemenize gerek yoktur. Otomatik konfigürasyon bunu halleder.

Öncelikle Order entity sınıfımıza siparişin durumunu tutacak bir alan ekleyelim. Çünkü servis çökerse siparişi "Başarılı" değil, "Beklemede" olarak kaydetmek istiyoruz.

// Order.java (Entity) içine ekleyin:
@Enumerated(EnumType.STRING)
private OrderStatus orderStatus; // PENDING, APPROVED, REJECTED

Şimdi OrderService.java sınıfını güncelleyelim:

@Service
public class OrderService {

    private final OrderRepository orderRepository;
    // Bu client, OpenFeign ile Customer Service'e HTTP isteği atar
    private final CustomerClient customerClient; 

    public OrderService(OrderRepository orderRepository, CustomerClient customerClient) {
        this.orderRepository = orderRepository;
        this.customerClient = customerClient;
    }

    // name = properties dosyasındaki instance ismiyle AYNI olmalı
    // fallbackMethod = Hata durumunda çalışacak metodun adı
    @CircuitBreaker(name = "customerService", fallbackMethod = "createOrderFallback")
    public Order createOrder(Order order) {

        // Customer Service'e (OpenFeign ile) istek atıyoruz
        var customerResponse = customerClient.getCustomerById(order.getCustomerId());
        CustomerDTO customer = customerResponse.getBody();

        System.out.println("Müşteri doğrulandı: " + customer.getFirstName());

        order.setOrderStatus(OrderStatus.APPROVED); // Her şey yolunda
        order.setCustomerName(customer.getFirstName());
        return orderRepository.save(order);
    }

    // --- FALLBACK METODU (B PLANI) ---
    // Customer Service cevap vermezse burası çalışır.
    public Order createOrderFallback(Order order, Exception e) {

        System.out.println("Customer Service cevap vermiyor! Fallback devreye girdi. Hata: " + e.getMessage());

        // KRİTİK NOKTA: Asla boş 'new Order()' dönmeyin!
        // Kullanıcı siparişinin alındığını ama henüz onaylanmadığını bilmeli.

        order.setOrderStatus(OrderStatus.PENDING); // Onay Bekliyor
        order.setCustomerName("Bilinmiyor");

        System.out.println("Sipariş 'PENDING' statüsünde kuyruğa alındı.");

        // Siparişi kaybetmiyoruz, veritabanına "Beklemede" olarak yazıyoruz.
        // Daha sonra bir zamanlanmış görev (Cron Job) bu siparişleri tekrar deneyebilir.
        return orderRepository.save(order);
    }
}

Senior İpucu: Hata Türüne Göre Davranış

Yukarıdaki örnekte tüm hataları (Exception e) yakaladık. Ancak profesyonel projelerde hatanın türüne göre farklı aksiyonlar alabilirsiniz:

  • **CallNotPermittedException:** Sigorta açık (OPEN) olduğu için istek reddedildi.
  • **TimeoutException:** İstek zaman aşımına uğradı.
// Sadece sigorta attığında çalışacak özel bir fallback yazabilirsiniz
public Order createOrderFallback(Order order, CallNotPermittedException e) {
    System.out.println("Sigorta şu an AÇIK, hiç istek atmadan reddedildi.");
    // ...
}

4. Adım: Büyük Test (Sigortayı Attıralım)

İşte en eğlenceli kısım. Sistemi gerçekten bozacağız ve ayakta kalıp kalmadığını göreceğiz.

  1. Her şeyi başlatın: Eureka, Gateway, Customer, Order.
  2. Mutlu Yol: Postman’den bir sipariş gönderin. Status APPROVED olarak dönmeli.
  3. Sabotaj: Customer Service uygulamasını DURDURUN (Stop).
  4. Test: Postman’den tekrar sipariş gönderin.

Sonuç ne olacak?

  • Eskiden: Uzun süre bekleyip 500 Internal Server Error alırdınız.
  • Şimdi: Sistem 2 saniye bekleyecek (Timeout), cevap alamayınca Fallback devreye girecek.
  • Postman size 200 OK dönecek ama dönen siparişin statüsü **PENDING** olacak.

Order Service çökmedi, müşteriyi mağdur etmedi, siparişi güvenli bir şekilde “Beklemeye” aldı. Sistem ayakta!

Kaynakça

  1. Resilience4j Documentation: https://resilience4j.readme.io/
  2. Spring Cloud Circuit Breaker: Spring Docs

Bana Ulaşmak İçin

Bu yazı ile ilgili sorularınız veya geri bildirimleriniz varsa, yorumlarda paylaşabilirsiniz. Ayrıca, diğer bağlantılarım ve projelerim için aşağıdaki bağlantılardan bana ulaşabilirsiniz.


메타데이터
post_id
e9ecf086ff4b
slug
java-ile-microservis-yolculuğu-5-sistem-çökmesin-e9ecf086ff4b
url
https://medium.com/@alper-bilgin/java-ile-microservis-yolculu%C4%9Fu-5-sistem-%C3%A7%C3%B6kmesin-e9ecf086ff4b
canonical_url
https://medium.com/@alper-bilgin/java-ile-microservis-yolculu%C4%9Fu-5-sistem-%C3%A7%C3%B6kmesin-e9ecf086ff4b
author_url
https://medium.com/@alper-bilgin
status
ok
fetched_at
2026-06-27 18:20:27