Uygulama yapısı
Dayanıklılık (Resilience)
Resilience.create zinciriyle yeniden deneme, zaman aşımı, devre kesici, bulkhead, oran sınırı ve fallback politikaları; sıralama, durum ve hata kodları.
Ağ istekleri ve dış kaynaklar başarısız olur, gecikir, aşırı yüklenir. Resilience, bu durumlar için altı politika sunar ve bunları tek bir zincirde birleştirir. Çerçevenin geri kalanından bağımsızdır; servislerde, veri katmanında ya da bir dataRequest içinde kullanılabilir.
import { Resilience } from "@motifx/core";
const policy = Resilience.create
.retry({ retries: 3, delay: 200 })
.timeout({ timeoutMs: 5000 })
.fallback({ fallback: () => [] });
const notes = await policy.execute(() => fetch("/api/notes").then((r) => r.json()));
import { Resilience } from "@motifx/core";
const policy = Resilience.create
.retry({ retries: 3, delay: 200 })
.timeout({ timeoutMs: 5000 })
.fallback({ fallback: () => [] });
const notes = await policy.execute(() => fetch("/api/notes").then((r) => r.json()));
Zincir ve sıralama
Resilience.create yeni, boş bir zincir verir; her politika metodu zincire ekler ve aynı nesneyi döndürür. execute(action, ctx?) eklenen politikaları eklenme sırasıyla dıştan içe sarar ve action'ı çalıştırır:
const load = () => fetch("/api/notes").then((r) => r.json());
Resilience.create.retry().timeout({ timeoutMs: 5000 }).execute(load);
// retry( timeout( load ) ): her deneme kendi zaman aşımına sahiptir
Resilience.create.timeout({ timeoutMs: 5000 }).retry().execute(load);
// timeout( retry( load ) ): bütün denemeler tek bir zaman aşımı içinde
const load = () => fetch("/api/notes").then((r) => r.json());
Resilience.create.retry().timeout({ timeoutMs: 5000 }).execute(load);
// retry( timeout( load ) ): her deneme kendi zaman aşımına sahiptir
Resilience.create.timeout({ timeoutMs: 5000 }).retry().execute(load);
// timeout( retry( load ) ): bütün denemeler tek bir zaman aşımı içinde
timeout ve fallback bir seçenek nesnesi ister (timeoutMs, fallback alanları zorunludur); diğer politikalarda seçenekler isteğe bağlıdır. action senkron ya da Promise döndürebilir; execute her zaman Promise döndürür. ctx serbest bir nesnedir (ResilienceContext), action(ctx) ve geri çağrılara olduğu gibi iletilir.
Tipler dışa aktarılır: seçenekler için RetryOptions, TimeoutOptions, CircuitBreakerOptions, BulkheadOptions, RateLimiterOptions, FallbackOptions<T>; devre durumu için CircuitState; execute imzası için ResiliencePolicy ve action için ResilienceAction<T>. Resilience sınıfı ResiliencePolicy'yi uygular; bir zinciri alan fonksiyonu (policy: ResiliencePolicy) => … diye tipleyin.
Durum zincirde yaşar. circuitBreaker, bulkhead ve rateLimiter çağrılar arasında sayaç tutar; her Resilience.create yeni sayaçlar açar. Bu politikaların işe yaraması için zinciri bir kez kurup (servis alanı, modül sabiti) her çağrıda aynı nesnenin execute'unu kullanın. retry, timeout ve fallback durumsuzdur.
@Injectable({ lifetime: 'singleton' })
export class ApiClient {
private policy = Resilience.create
.circuitBreaker({ failureThreshold: 5, durationOfBreakMs: 30000 })
.retry({ retries: 2 })
.timeout({ timeoutMs: 8000 });
get<T>(url: string): Promise<T> {
return this.policy.execute(() => fetch(url).then((r) => r.json()));
}
}
@Injectable({ lifetime: 'singleton' })
export class ApiClient {
policy = Resilience.create
.circuitBreaker({ failureThreshold: 5, durationOfBreakMs: 30000 })
.retry({ retries: 2 })
.timeout({ timeoutMs: 8000 });
get(url) {
return this.policy.execute(() => fetch(url).then((r) => r.json()));
}
}
Bu sırada her deneme kendi 8 saniyelik zaman aşımıyla çalışır. Zaman aşımı varsayılan olarak ne yeniden denenir ne de devre için başarısızlık sayılır; yanıt vermeyen bir sunucuda devrenin açılması isteniyorsa circuitBreaker'a shouldHandle: () => true verilir.
Politikalar
retry(seçenekler?)
Başarısız action'ı bekleyip yeniden dener.
| Seçenek | Varsayılan | Açıklama |
|---|---|---|
retries |
3 |
Yeniden deneme sayısı; toplam deneme retries + 1. |
backoff |
'exponential' |
'exponential': delay × 2^(deneme−1); 'fixed': her seferinde delay; 'none': bekleme yok. |
delay |
100 |
Taban bekleme (ms). |
jitter |
0.1 |
Beklemeye eklenen rastgele pay oranı (0–1): bekleme ± jitter × bekleme aralığında sapar. |
shouldHandle |
zaman aşımı dışındaki her hata | (hata) => boolean; false dönerse yeniden denenmez, hata hemen fırlatılır. Varsayılan TimeoutError'u (timeout politikasının hatası) ve undefined/null ile yapılan reddi yeniden denemez. |
onRetry |
— | (deneme, hata, beklemeMs, ctx); her beklemeden önce çağrılır, Promise döndürürse beklenir. |
Son deneme de başarısız olursa son hata fırlatılır. Zaman aşımına uğrayan isteği de yeniden denemek için shouldHandle: () => true verin.
`timeout(
action timeoutMs içinde bitmezse MJX605 kodlu, name'i 'TimeoutError' olan bir MotifError fırlatılır. Süren işlem iptal edilmez (fetch için AbortController'ı kendiniz bağlayın); yalnız sonucu beklenmez. Zamanlayıcı her iki durumda da temizlenir.
circuitBreaker(seçenekler?)
Arka arkaya başarısızlıkta çağrıları bir süre hiç yapmadan reddeder; kaynağa toparlanma payı verir.
| Seçenek | Varsayılan | Açıklama |
|---|---|---|
failureThreshold |
5 |
CLOSED durumda bu kadar ardışık başarısızlık devreyi açar. Araya giren başarı sayacı sıfırlar. |
successThreshold |
2 |
HALF_OPEN durumda bu kadar ardışık başarı devreyi kapatır. |
durationOfBreakMs |
60000 |
OPEN durumun süresi; dolunca ilk çağrı HALF_OPEN'a geçer. |
shouldHandle |
zaman aşımı dışındaki her hata | Hangi hataların başarısızlık sayılacağı. Varsayılan TimeoutError'u ve undefined/null ile yapılan reddi saymaz. |
onStateChange |
— | (eski, yeni); 'CLOSED' \| 'OPEN' \| 'HALF_OPEN'. |
OPEN durumda execute action'ı çağırmadan MJX602 fırlatır. HALF_OPEN'da tek bir başarısızlık devreyi yeniden açar. Devre durumunu onStateChange ile izleyin; zincirin bir "durum oku" metodu yoktur.
bulkhead(seçenekler?)
Aynı anda çalışan action sayısını sınırlar; fazlası kuyruğa girer.
| Seçenek | Varsayılan | Açıklama |
|---|---|---|
maxConcurrent |
10 |
Eşzamanlı üst sınır. |
maxQueue |
50 |
Bekleme kuyruğu üst sınırı; dolunca MJX603 fırlatılır. |
Kuyruk FIFO'dur; bir çağrı bitince sıradaki başlar.
rateLimiter(seçenekler?)
Jeton kovası: her çağrı bir jeton harcar, jetonlar aralıklarla dolar.
| Seçenek | Varsayılan | Açıklama |
|---|---|---|
tokensPerInterval |
1 |
Her aralıkta eklenen jeton. |
intervalMs |
1000 |
Aralık. |
capacity |
tokensPerInterval |
Kova kapasitesi; başlangıçta kova doludur. Patlama (burst) payı istenirse daha büyük verin. |
Jeton yoksa execute beklemez, MJX604 fırlatır. Varsayılan değerler "saniyede en çok 1" demektir; "saniyede en çok N" için tokensPerInterval: N yeter. capacity: 10, tokensPerInterval: 1 ise ilk 10 çağrıyı anında geçirir, sonra saniyede 1 verir.
fallback({ fallback, shouldHandle? })
action başarısız olursa fallback(hata, ctx)'in döndürdüğü değer (senkron ya da Promise) sonuç olur. shouldHandle (varsayılan her hata) false dönerse hata fırlatılır. Zincirin ilk sırasına konursa içteki bütün politikaların son hatasını yakalar.
decorate(policy, fn)
Bir zinciri fonksiyona bağlayıp yeniden kullanılabilir hâle getirir:
import { Resilience, decorate } from "@motifx/core";
const loadNotes = decorate(
Resilience.create.retry({ retries: 2 }).timeout({ timeoutMs: 5000 }),
() => fetch("/api/notes").then((r) => r.json()),
);
const notes = await loadNotes(); // policy.execute(fn, ctx) ile aynı
import { Resilience, decorate } from "@motifx/core";
const loadNotes = decorate(
Resilience.create.retry({ retries: 2 }).timeout({ timeoutMs: 5000 }),
() => fetch("/api/notes").then((r) => r.json()),
);
const notes = await loadNotes(); // policy.execute(fn, ctx) ile aynı
decorate(policy: ResiliencePolicy, fn: ResilienceAction<T>) ilk argüman olarak execute(action, ctx?) metodu olan her nesneyi kabul eder; Resilience zinciri bu arabirimi uygular.
Hata kodları
| Kod | Politika | Anlamı |
|---|---|---|
MJX602 |
circuitBreaker |
Devre açık; action çağrılmadı. |
MJX603 |
bulkhead |
Kuyruk dolu. |
MJX604 |
rateLimiter |
Jeton yok. |
MJX605 |
timeout |
Zaman aşımı (name: 'TimeoutError'). |
Dördü de MotifError'dur ve execute'tan fırlatılır; fallback ile yakalanabilir. retry ve circuitBreaker varsayılan shouldHandle ile zaman aşımını saymaz, diğer üçünü sayar.
Sonraki adım
Sayfalar arası yönlendirmeyi öğrenmek için Yönlendirmeye Giriş bölümüne geçin.