---
title: 'Yeniden Deneme ve Geri Çekilme'
source: 'https://academia.sh/tr/kurslar/gozlemlenebilirlik/yeniden-deneme-ve-geri-cekilme'
course: 'Gözlemlenebilirlik ve Güvenilirlik'
language: tr
updated: '2026-08-17T18:06:51+00:00'
license: 'CC BY-SA 4.0'
---

# Yeniden Deneme ve Geri Çekilme

Yeniden denemenin hangi katmanda durduğunun ölçülmesi: aynı kuralın istemci sarmalayıcısında, ara katmanda ve ağ geçidinde ayrı ayrı kurulması, sağlıklı çağrı yerinin yeniden denenip denenmediği, üst üste binen üç yerleşimin çarpımı ve tekrarlanan yan etkinin teslim cinsinden sayılması.

Bir önceki ders süre sınırını koydu ve çağıranı serbest bıraktı, ama elinde bir hata kaldı. En
yakın karşılık yeniden denemektir: bağımlılık geçici olarak düşmüşse ikinci çağrı başarılı olabilir.
Bu kararın da bir yeri vardır ve zaman aşımından daha tehlikelidir — zaman aşımı bağımlılığın
yükünü değiştirmiyordu, yeniden deneme onu doğrudan çarpar.

Üstel geri çekilme, sarsıntı, tavan ve deneme bütçesi aritmetiği **M14/K06 Uygulama Mimarisi**,
**M16/K05** ve **M19/K05 Dayanıklılık ve Güvenilirlik** kurslarında kuruldu; kalıbın sistem
üzerindeki etkisi de M19/K05'te ölçüldü. Burada tekrarlanmaz. Bu dersin sorusu tektir: **yeniden
deneme hangi katmanda duruyor** ve o katman değiştiğinde bağımlılığa giden çağrı ne oluyor.

Aynı kural üç yere kurulabilir. **İstemci sarmalayıcısı** tek bir dış çağrıyı yeniden dener. **Ara
katman** isteğin gövdesini bütünüyle yeniden çalıştırır. **Ağ geçidi** servisin tamamını yeniden
çağırır ve servisin kodunda tek satırı yoktur. Üçü de aynı sözü verir; üçü de farklı bir şeyi
tekrarlar.

## Düzenek

Bildirim bağımlılığı bu dersin ölçüsünü taşır. **DY5 — bildirim teslimi gerçekten yapar, kaybolan
şey onaydır:** her çağrıda teslim sayacı artar, ama ilk `ariza` çağrıda 503 döner. Böylece yeniden
denemenin tekrarladığı şey yalnız çağrı değil, **yan etkidir**. Üyelik sağlıklı bir bağımlılıktır
ve her zaman yanıt verir.

```js
// servisler.mjs — 8202 bildirim (arizali, teslimi sayar), 8203 uyelik (saglikli),
// 8201 odunc: iki yeniden deneme yerlesimini de tasir. Sayaclar 8202/sayac ucundadir.
import { createServer, request } from "node:http";
const s = { odunc: 0, uyelik: 0, bildirim: 0, teslim: 0, kalan: 0 };  // teslim: bildirimin gercekten gonderdigi
createServer((i, y) => {                            // 8202 bildirim
  const q = new URL(i.url, "http://x").searchParams;
  if (i.url === "/sayac") return y.end(JSON.stringify(s));
  if (i.url.startsWith("/sifirla")) {
    for (const k of ["odunc", "uyelik", "bildirim", "teslim"]) s[k] = 0;
    s.kalan = Number(q.get("ariza")); return y.end("{}");
  }
  s.bildirim += 1; s.teslim += 1;                   // teslim yapilir; onay ilk `kalan` cagride kaybolur
  if (s.kalan > 0) { s.kalan -= 1; y.statusCode = 503; }
  y.end("{}");
}).listen(8202);
createServer((i, y) => { s.uyelik += 1; y.end("{}"); }).listen(8203);   // saglikli bagimlilik

const cagir = (port, yol) => new Promise((coz) => {
  const r = request({ port, path: yol, agent: false }, (y) => { y.resume(); y.on("end", () => coz(y.statusCode)); });
  r.on("error", () => coz(0)); r.end();
});
// >>> yerlesim: istemci sarmalayicisi — yalniz sardigi cagri yerini yeniden dener
const istek = async (port, yol, deneme) => {
  for (let n = 1; ; n += 1) {
    const k = await cagir(port, yol);
    if (k < 500 || n >= deneme) return k;
  }
};
// <<<
const isle = async (ic) => {                        // odunc isteginin govdesi: iki dis cagri yeri
  await istek(8203, "/uye", 1);                     // saglikli bagimlilik, yeniden denenmez
  return istek(8202, "/gonder", ic);
};
createServer(async (i, y) => {                      // 8201 odunc
  const q = new URL(i.url, "http://x").searchParams;
  s.odunc += 1;
  // >>> yerlesim: ara katman — istegin govdesini butunuyle yeniden calistirir
  let k = 0;
  for (let n = 1; n <= Number(q.get("ara")); n += 1) { k = await isle(Number(q.get("ic"))); if (k < 500) break; }
  // <<<
  y.statusCode = k; y.end("{}");
}).listen(8201);
```

Üçüncü yerleşim ölçüm betiğindedir, çünkü ağ geçidi servisin dışındadır. **DY6 — her katmanın
deneme sayısı 3'tür**; kıyas ancak sayı sabitken anlamlıdır. `>>> yerlesim:` işaretleri kod bedelini
saymak içindir, betik onları kaynaktan okur.

```js
// olc.mjs — yeniden denemenin hangi katmanda durdugu, ust uste binen denemenin carpimi, kod bedeli.
import { readFileSync } from "node:fs";
import { request } from "node:http";
const cagir = (port, yol) => new Promise((coz) => {
  const r = request({ port, path: yol, agent: false }, (y) => { y.resume(); y.on("end", () => coz(y.statusCode)); });
  r.on("error", () => coz(0)); r.end();
});
const oku = (yol) => new Promise((c) => request({ port: 8202, path: yol }, (r) => {
  let g = ""; r.on("data", (p) => (g += p)); r.on("end", () => c(g === "{}" ? null : JSON.parse(g)));
}).end());
const yaz = (g, a, ...r) => console.log(String(a).padEnd(24) + r.map((x) => String(x).padStart(g)).join(""));
// >>> yerlesim: ag gecidi — servisin kodunda tek satir yoktur
const gecit = async (dis, ara, ic) => {
  for (let n = 1; ; n += 1) {
    const k = await cagir(8201, `/odunc?ara=${ara}&ic=${ic}`);
    if (k < 500 || n >= dis) return k;
  }
};
// <<<
const dene = async (ariza, dis, ara, ic) => {
  await oku(`/sifirla?ariza=${ariza}`);
  const k = await gecit(dis, ara, ic);
  return { k, ...(await oku("/sayac")) };
};

console.log("gecici ariza: bildirim ilk 2 cagride teslim eder ama onay kaybolur; tek kullanici istegi");
yaz(15, "yerlesim (dis/ara/ic)", "sonuc", "odunc cagri", "uyelik cagri", "bildirim cagri", "teslim");
for (const [ad, d, a, i] of [["yok (1/1/1)", 1, 1, 1], ["sarmalayici (1/1/3)", 1, 1, 3],
  ["ara katman (1/3/1)", 1, 3, 1], ["ag gecidi (3/1/1)", 3, 1, 1]]) {
  const r = await dene(2, d, a, i);
  yaz(15, ad, r.k, r.odunc, r.uyelik, r.bildirim, r.teslim);
}

console.log("\nkalici ariza: ust uste binen yeniden deneme");
yaz(15, "dis / ara / ic", "carpim", "bildirim cagri", "teslim", "uyelik cagri");
for (const [d, a, i] of [[1, 1, 1], [3, 1, 1], [3, 3, 1], [3, 3, 3], [5, 3, 3]]) {
  const r = await dene(999, d, a, i);
  yaz(15, `${d} / ${a} / ${i}`, d * a * i, r.bildirim, r.teslim, r.uyelik);
}

const kod = (dosya) => [...readFileSync(dosya, "utf8").matchAll(/\/\/ >>> yerlesim: ([^\n—]+)—[^\n]*\n([\s\S]*?)\/\/ <<</g)]
  .map(([, ad, g]) => [ad.trim(), dosya, g.trim().split("\n").length]);
const cy = [...readFileSync("servisler.mjs", "utf8").matchAll(/istek\(\d+, "[^"]+", ([^)]+)\)/g)].map((m) => m[1]);
console.log("\nkod bedeli ve kapsam");
yaz(15, "yerlesim", "dosya", "satir");
for (const [ad, d, n] of [...kod("servisler.mjs"), ...kod("olc.mjs")]) yaz(15, ad, d, n);
console.log(`odunc govdesinde ${cy.length} dis cagri yeri var; sarmalayici ${cy.filter((x) => x !== "1").length} ` +
  `tanesini yeniden deniyor, ara katman ve ag gecidi ${cy.length} tanesini de.`);
console.log("yapilandirma yuzeyi: 3 deneme sayisi, 3 ayri yerde; hicbiri otekinin degerini gormuyor.");
process.exit(0);
```

```bash
node servisler.mjs > /dev/null 2>&1 & SP=$!
sleep 1; node olc.mjs; kill $SP
```

```
gecici ariza: bildirim ilk 2 cagride teslim eder ama onay kaybolur; tek kullanici istegi
yerlesim (dis/ara/ic)             sonuc    odunc cagri   uyelik cagri bildirim cagri         teslim
yok (1/1/1)                         503              1              1              1              1
sarmalayici (1/1/3)                 200              1              1              3              3
ara katman (1/3/1)                  200              1              3              3              3
ag gecidi (3/1/1)                   200              3              3              3              3

kalici ariza: ust uste binen yeniden deneme
dis / ara / ic                   carpim bildirim cagri         teslim   uyelik cagri
1 / 1 / 1                             1              1              1              1
3 / 1 / 1                             3              3              3              3
3 / 3 / 1                             9              9              9              9
3 / 3 / 3                            27             27             27              9
5 / 3 / 3                            45             45             45             15

kod bedeli ve kapsam
yerlesim                          dosya          satir
istemci sarmalayicisi     servisler.mjs              6
ara katman                servisler.mjs              2
ag gecidi                       olc.mjs              6
odunc govdesinde 2 dis cagri yeri var; sarmalayici 1 tanesini yeniden deniyor, ara katman ve ag gecidi 2 tanesini de.
yapilandirma yuzeyi: 3 deneme sayisi, 3 ayri yerde; hicbiri otekinin degerini gormuyor.
```

## Üç Yerleşim Aynı Arızayı Nasıl Kapatıyor

İlk tablo geçici bir arızayı üç yerleşimle karşılıyor ve **sonuç sütunu üçünde de aynı**: 503 olan
istek 200'e dönüyor. Yeniden deneme sözünü tutuyor. Fark öteki sütunlardadır.

**Bağımlılığa giden çağrı üçünde de 3.** Bu şaşırtıcı değildir; arıza iki çağrı sürüyor, üçüncüde
geçiyor. Yeniden denemenin bağımlılık üzerindeki yükü, yerleşimden değil deneme sayısından gelir.

**Sağlıklı bağımlılığa giden çağrı ise 1, 3 ve 3.** Ayrım buradadır. İstemci sarmalayıcısı yalnız
sardığı çağrı yerini yeniden dener; üyelik çağrısı bir kez yapılır ve arızayla hiç ilgisi olmayan
o bağımlılık hiç zorlanmaz. Ara katman isteğin gövdesini baştan çalıştırır, dolayısıyla **arızasız
çağrı yerini de** tekrarlar. Ağ geçidi aynısını yapar ve üstüne ödünç servisini de üç kez çağırır —
tabloda `odunc cagri` sütununda 1, 1, 3 olarak görünür.

Bundan çıkan kural bir seçim ölçütüdür: **dıştaki yerleşim ayrım yapamaz.** Ağ geçidi hangi çağrının
başarısız olduğunu bilmez, isteğin tamamını tekrarlar; ne kadar dışarı çıkılırsa tekrarlanan iş o
kadar büyür. İçteki yerleşim ayrım yapar ama yalnız kendisinden geçen çağrı yerini kapsar — bir
önceki dersin atlanan çağrı yeri sorunu burada da aynen geçerlidir.

**Teslim sütunu üç yerleşimde de 3.** Tek bir kullanıcı isteği için bildirim üç kez gönderilmiştir.
Yerleşimi değiştirmek bunu düzeltmiyor; bu yan etki yeniden denemenin kendisinden geliyor. Bir çağrı
yerinin tekrarlanabilir olup olmadığı yerleşimin değil, çağrı yerinin özelliğidir ve düzeltmesi de
oradadır: o çağrı yeri deneme sayısını 1'de tutmalıdır.

## Üst Üste Binen Yeniden Deneme

İkinci tablo üç yerleşimi aynı anda açıyor. Kalıcı arızada her katman kendi payını sonuna kadar
harcıyor ve bağımlılığa giden çağrı **çarpım sütununu birebir izliyor**: 1, 3, 9, 27, 45. Tek bir
kullanıcı isteği bağımlılıkta 27 çağrıya dönüşüyor ve tek bir bildirim 27 kez teslim ediliyor.

Bu tablonun asıl bilgisi çarpımın kendisi değil, **hiçbir katmanın onu görmemesidir**. Ağ geçidini
yazan üç deneme yazdı, ara katmanı yazan üç deneme yazdı, sarmalayıcıyı yazan üç deneme yazdı;
hiçbiri yanlış bir sayı seçmedi. Yapılandırma yüzeyi üç ayrı yerdedir ve hiçbiri ötekinin değerini
göremez. Son satır bunun ne kadar hızlı büyüdüğünü söylüyor: dıştaki katman üçten beşe çıktığında
toplam 27'den 45'e gidiyor, yani **tek bir sayının tek bir yerde değişmesi bağımlılıkta on sekiz
çağrı ekliyor**.

`uyelik cagri` sütunu aynı satırlarda 9'dur, 27 değil. Sağlıklı bağımlılık yalnız dış iki katmanın
çarpımı kadar çağrılıyor, çünkü en içteki yerleşim onu tekrarlamıyor. Çarpımın hangi çarpanlarının
hangi çağrı yerine uygulandığı, yerleşimin doğrudan sonucudur.

## Kod Bedeli ve Kapsam

Üçüncü tablo yerleşimlerin koddaki büyüklüğünü veriyor: istemci sarmalayıcısı 6 satır, ara katman 2
satır, ağ geçidi 6 satır — ve ağ geçidinin altı satırı **servisin kodunda değildir**. Bu, dıştaki
yerleşimi çekici kılan şeydir: servis hiç değişmeden bütün çağrı yerleri kapsanır, hatta henüz
yazılmamış olanlar bile. Bedeli de tam olarak budur; kapsamın seçici olmaması bir eksiklik değil,
o yerleşimin tanımıdır.

İçteki yerleşim tersidir: ödünç gövdesindeki iki dış çağrı yerinden birini yeniden deniyor, ötekini
bilerek bırakıyor. Seçicilik ancak her çağrı yerine tek tek karar verilerek elde edilir ve bu karar
bir kez verilmez — yeni bir çağrı yeri eklendiğinde yeniden verilir.

## Sınanabilirlik

Yerleşim, davranışın testte nereye bağlanabileceğini de belirler.

```js
// test/deneme.test.mjs — yerlesimin sinanabilirligi: iddia nereye baglaniyor.
import { test } from "node:test";
import assert from "node:assert/strict";
import { request } from "node:http";
const cagir = (port, yol) => new Promise((coz) => {
  const r = request({ port, path: yol, agent: false }, (y) => { y.resume(); y.on("end", () => coz(y.statusCode)); });
  r.on("error", () => coz(0)); r.end();
});
const oku = (yol) => new Promise((c) => request({ port: 8202, path: yol }, (r) => {
  let g = ""; r.on("data", (p) => (g += p)); r.on("end", () => c(g === "{}" ? null : JSON.parse(g)));
}).end());
const kos = async (ariza, dis, ara, ic) => {
  await oku(`/sifirla?ariza=${ariza}`);
  for (let n = 1; n <= dis; n += 1) if (await cagir(8201, `/odunc?ara=${ara}&ic=${ic}`) < 500) break;
  return oku("/sayac");
};

test("sarmalayici yerlesimi: iddia tek cagri yerine baglanir", async () => {
  assert.equal((await kos(2, 1, 1, 3)).bildirim, 3);
  assert.equal((await kos(2, 1, 1, 3)).uyelik, 1);   // saglikli cagri yeri yeniden denenmez
});
test("ag gecidi yerlesimi: ayni iddia ic ayarla degisir", async () => {
  assert.equal((await kos(999, 3, 1, 1)).bildirim, 3);
  assert.equal((await kos(999, 3, 1, 3)).bildirim, 9);   // ag gecidi ayni, sonuc uc kati
});
test("yeniden deneme teslimi cogaltir", async () => {
  const r = await kos(2, 1, 1, 3);
  assert.equal(r.teslim, 3);                        // tek kullanici istegi, uc teslim
});
```

```bash
node servisler.mjs > /dev/null 2>&1 & SP=$!
sleep 1
node --test --test-force-exit --test-reporter=tap test/deneme.test.mjs |
  grep -E "^(ok|not ok|# (tests|pass|fail) )"
kill $SP
```

```
ok 1 - sarmalayici yerlesimi: iddia tek cagri yerine baglanir
ok 2 - ag gecidi yerlesimi: ayni iddia ic ayarla degisir
ok 3 - yeniden deneme teslimi cogaltir
# tests 3
# pass 3
# fail 0
```

İlk test sarmalayıcı yerleşiminin sınanabilirliğini gösteriyor: iddia tek bir çağrı yerine
bağlanır, sayı yereldir ve başka hiçbir ayar onu değiştiremez. İkinci test ağ geçidi yerleşiminin
sorununu **testin kendisiyle** kanıtlıyor: ağ geçidinin ayarı iki koşumda da 3'tür, ama beklenen
çağrı sayısı 3'ten 9'a çıkar, çünkü içeride başka bir sayı değişmiştir. Dıştaki yerleşimin davranışı
hakkında yazılan bir iddia, kendisinin görmediği bir ayara bağımlıdır ve o ayar değiştiğinde test
kırılır. Üçüncü test yan etkiyi doğrudan sabitliyor: bir kullanıcı isteği, üç teslim.

## Özet

- Yeniden denemenin aritmetiği ve sistem üzerindeki etkisi M14/K06, M16/K05 ve M19/K05
  Dayanıklılık ve Güvenilirlik kurslarında ölçüldü; burada ölçülen hangi katmanda durduğudur.
- Geçici arızada üç yerleşim de isteği kurtarır ve bağımlılığa giden çağrı üçünde de 3'tür; fark
  sağlıklı bağımlılığa giden çağrıdadır: sarmalayıcıda 1, ara katmanda 3, ağ geçidinde 3. Ağ geçidi
  ayrıca ödünç servisini 1 yerine 3 kez çağırır.
- Dıştaki yerleşim ayrım yapamaz: hangi çağrının başarısız olduğunu bilmediği için isteğin tamamını
  tekrarlar. İçteki yerleşim ayrım yapar ama yalnız kendisinden geçen çağrı yerini kapsar.
- Üç yerleşim aynı anda açıldığında bağımlılığa giden çağrı çarpımı birebir izler: 1, 3, 9, 27, 45.
  Hiçbir katman ötekinin sayısını görmez; dıştaki sayının üçten beşe çıkması bağımlılıkta on sekiz
  çağrı ekler. Sağlıklı bağımlılık aynı satırlarda 9 çağrı alır, 27 değil.
- Teslim sayacı üç yerleşimde de 3'tür: tekrarlanan yan etki yerleşimin değil, çağrı yerinin
  sorunudur ve çözümü o çağrı yerinin deneme sayısını 1'de tutmaktır.
- Kod bedeli 6 / 2 / 6 satırdır ve ağ geçidinin altı satırı servisin kodunda değildir. Testte
  sarmalayıcı yerleşiminin iddiası yereldir; ağ geçidi yerleşiminin iddiası görmediği bir ayara
  bağlıdır ve o ayar değişince kırılır.

## Sonraki Adım

Yeniden deneme geçici arızayı kapatıyor ama kalıcı arızada durumu ağırlaştırıyor: 27 çağrının 27'si
de başarısız oldu, hiçbiri bir şey kurtarmadı ve bağımlılık zaten düşmüşken üzerine yirmi yedi kat
yük bindi. Eksik olan şey bir sayı değil, bir **karardır** — bağımlılığın düştüğünü anlayıp çağrıyı
hiç yapmamak. Sonraki ders devre kesiciyi koda yerleştirir ve şunu ölçer: kesicinin durumu bağımlılık
başına mı yoksa çağrı yeri başına mı tutuluyor, aynı arızada iki yerleşim ne zaman açılıyor,
yapılandırma yüzeyi kaç parametre ve yanlış eşik hangi davranışı üretiyor.
