Skip to content

Retry Politikaları & Circuit Breaker

Dağıtık sistemlerde ağ kararsızlığı kaçınılmazdır. Bu kütüphane iki tamamlayıcı dayanıklılık mekanizması sunar: geçici hatalar için Retry Politikaları ve tamamen çökmüş bir servise karşı basamaklı hataları önlemek için Circuit Breaker.

Retry Politikaları

Yerleşik Politikalar

PolitikaFactoryDavranış
Exponential BackoffRetryPolicies.exponential(attempts)Her denemede gecikme iki katına çıkar ve küçük jitter eklenir — çoğu durum için varsayılan seçim
Fixed DelayRetryPolicies.fixedDelay(attempts, delayMs)Her yeniden deneme arasında sabit bekleme
Linear BackoffRetryPolicies.linearBackoff(attempts, stepMs)Gecikme doğrusal olarak büyür (deneme × stepMs)
Full JitterRetryPolicies.fullJitter(attempts, baseMs)Üstel sınır içinde tamamen rastgele gecikme — eşzamanlı yükü yaymak için en iyi seçim
Decorrelated JitterRetryPolicies.decorrelatedJitter(attempts, baseMs, maxDelayMs)Eşzamanlı istemciler arasında en geniş yayılımı sağlayan AWS tarafından önerilen algoritma

Tüm politikalar varsayılan olarak 429, 502, 503, 504 ve ağ hatalarında yeniden dener.

typescript
import { RetryPolicies } from '@yildizpay/http-adapter';

RetryPolicies.exponential(3);
RetryPolicies.fixedDelay(3, 1_000);          // Her deneme arasında 1 saniye
RetryPolicies.linearBackoff(3, 500);         // 500 ms → 1000 ms → 1500 ms
RetryPolicies.fullJitter(3, 100);            // [0, 2^deneme × 100 ms] aralığında rastgele
RetryPolicies.decorrelatedJitter(3, 100);    // AWS dekorelasyonlu jitter, maks 30 s

Özel Retry Koşulu

.retryIf() ile herhangi bir politika için varsayılan yeniden deneme kararını (error.isRetryable()) geçersiz kılabilirsiniz. Satır içi bir fonksiyon veya RetryPredicate uygulayan bir sınıf kabul eder:

typescript
import {
  RetryPolicies,
  RetryPredicate,
  BaseAdapterException,
  isNetworkException,
} from '@yildizpay/http-adapter';

// Satır içi fonksiyon — yalnızca ağ seviyesindeki hatalarda yeniden dene
const policy = RetryPolicies.exponential(3)
  .retryIf((error) => isNetworkException(error));

// Sınıf tabanlı predicate — kütüphane sinyalini kendi mantığınızla birleştirin
class IsRetryPredicate implements RetryPredicate {
  shouldRetry(error: BaseAdapterException): boolean {
    return error.isRetryable() && featureFlags.retriesEnabled();
  }
}

const policy = RetryPolicies.fullJitter(3, 100)
  .retryIf(new IsRetryPredicate());

Adapter'a Retry Politikası Ekleme

typescript
const adapter = HttpAdapter.builder()
  .withRetryPolicy(RetryPolicies.exponential(3))
  .build();

Circuit Breaker

Circuit Breaker, sisteminizi tamamen çökmüş bir downstream servisi beklemekten korur. Yapılandırılan sayıda ardışık başarısızlıktan sonra devre açılır ve ardından gelen istekler, yanıt vermeyen sunucuya istek atmadan CircuitBreakerOpenException ile anında başarısız olur.

Yapılandırma

typescript
import { CircuitBreaker, CircuitBreakerOpenException } from '@yildizpay/http-adapter';

const breaker = new CircuitBreaker({
  failureThreshold: 5,    // 5 ardışık başarısızlıktan sonra devreyi aç
  resetTimeoutMs: 30_000, // 30 saniye sonra tekrar prob yap
  successThreshold: 1,    // 1 başarılı probdan sonra devreyi kapat
});
typescript
try {
  await adapter.send(request);
} catch (err) {
  if (err instanceof CircuitBreakerOpenException) {
    console.warn(`Devre açık. ${err.retryAfterMs()}ms sonra tekrar deneyin`);
  }
}

Durum Makinesi

  [CLOSED] ──(failureThreshold aşıldı)──▶ [OPEN]
     ▲                                       │
     │                               (resetTimeoutMs)
     │                                       │
     └──(successThreshold karşılandı)── [HALF_OPEN] ──(başarısızlık)──▶ [OPEN]
DurumDavranış
CLOSEDNormal çalışma. Başarısızlıklar sayılır.
OPENTüm istekler anında CircuitBreakerOpenException ile başarısız olur.
HALF_OPENBir prob isteğinin geçmesine izin verilir. Başarı → CLOSED. Başarısızlık → OPEN.

Neden HALF_OPEN'da Yalnızca Tek Bir Prob?

Node.js'in async/await'i işbirlikli çoklu görev başlatır: bir coroutine bir await'te askıya alınırken, olay döngüsü diğer coroutine'leri başlatabilir. Bir koruma olmadan, HALF_OPEN sırasında gelen her istek aynı durumu okuyup eşzamanlı olarak devam ederdi — bu da henüz kurtulmakta olan bir servisi bunaltabilir.

Circuit Breaker bir prob bayrağı kullanır: yalnızca ilk çağıran prob slotunu alır. HALF_OPEN'daki tüm eşzamanlı çağıranlar, prob çözümlenene kadar CircuitBreakerOpenException alır. Bu kasıtlı bir denge — kontrollü, güvenli bir iyileşme testi karşılığında birkaç ekstra ret.

Adapter'a Ekleme

typescript
const adapter = HttpAdapter.builder()
  .withCircuitBreaker({
    failureThreshold: 5,
    resetTimeoutMs: 30_000,
    successThreshold: 1,
  })
  .build();

Observer da eklemek istiyorsanız CircuitBreaker instance'ı oluşturun:

typescript
const breaker = new CircuitBreaker({ failureThreshold: 5, resetTimeoutMs: 30_000 })
  .observe(new CircuitMetricsObserver());

const adapter = HttpAdapter.builder()
  .withCircuitBreaker(breaker)
  .build();

CircuitBreakerObserver API'si için Gözlemlenebilirlik sayfasına bakın.

Released under the MIT License.