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
| Politika | Factory | Davranış |
|---|---|---|
| Exponential Backoff | RetryPolicies.exponential(attempts) | Her denemede gecikme iki katına çıkar ve küçük jitter eklenir — çoğu durum için varsayılan seçim |
| Fixed Delay | RetryPolicies.fixedDelay(attempts, delayMs) | Her yeniden deneme arasında sabit bekleme |
| Linear Backoff | RetryPolicies.linearBackoff(attempts, stepMs) | Gecikme doğrusal olarak büyür (deneme × stepMs) |
| Full Jitter | RetryPolicies.fullJitter(attempts, baseMs) | Üstel sınır içinde tamamen rastgele gecikme — eşzamanlı yükü yaymak için en iyi seçim |
| Decorrelated Jitter | RetryPolicies.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.
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:
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
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
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
});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]| Durum | Davranış |
|---|---|
CLOSED | Normal çalışma. Başarısızlıklar sayılır. |
OPEN | Tüm istekler anında CircuitBreakerOpenException ile başarısız olur. |
HALF_OPEN | Bir 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
const adapter = HttpAdapter.builder()
.withCircuitBreaker({
failureThreshold: 5,
resetTimeoutMs: 30_000,
successThreshold: 1,
})
.build();Observer da eklemek istiyorsanız CircuitBreaker instance'ı oluşturun:
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.
