---
title: 'Devre Kesici'
source: 'https://academia.sh/tr/kurslar/gozlemlenebilirlik/devre-kesici'
course: 'Gözlemlenebilirlik ve Güvenilirlik'
language: tr
updated: '2026-08-17T18:06:51+00:00'
license: 'CC BY-SA 4.0'
---

# Devre Kesici

Kesicinin kodda nereye yerleştiğinin ölçülmesi: durumun bağımlılık başına mı çağrı yeri başına mı tutulduğu, iki yerleşimde açılmaya kadar bağımlılığa giden çağrı, aynı eşiğin iki yerleşimde iki ayrı anlam taşıması ve seyrek çağrılan bir yolun kesicisinin hiç açılmaması.

Bir önceki ders yeniden denemenin kalıcı arızada durumu ağırlaştırdığını ölçtü: 27 çağrının 27'si
başarısız oldu ve düşmüş bir bağımlılığın üzerine yirmi yedi kat yük bindi. Eksik olan bir sayı
değil, bir karardır — bağımlılığın düştüğünü anlayıp çağrıyı hiç yapmamak.

Devre kesicinin ne olduğu, kapalı, açık ve yarı açık durumları **M14/K06 Uygulama Mimarisi**
kursunda kuruldu; kalıbın sistem üzerindeki etkisi, arızasız günün bedeli ve yanlış açılmanın
maliyeti **M19/K05 Dayanıklılık ve Güvenilirlik** kursunda ölçüldü. İkisi de burada tekrarlanmaz.
Bu dersin sorusu şudur: kesicinin **durumu nerede tutuluyor**. Bir kesici bir sayı ve bir zaman
damgasından ibarettir; o sayının nereye konduğu kalıbın ne yaptığını baştan belirler.

İki yerleşim vardır ve aralarındaki fark koddaki tek bir simgedir: durum **bağımlılık adıyla** mı
saklanıyor, yoksa **çağrı yeri adıyla** mı. Ödünç servisi aynı bildirim bağımlılığına üç ayrı çağrı
yerinden gidiyor; birinci yerleşimde üçü tek bir durumu paylaşır, ikincisinde her biri kendi
durumunu tutar.

## Düzenek

Bildirim bağımlılığı kalıcı olarak arızalıdır ve her çağrıya 503 döner. Katalog sağlıklıdır ve
kesiciden geçmesine rağmen hiç açılmaz — kesicinin kapsamının nerede bittiğini göstermek için
oradadır. **DY7 — kesik süresi koşumdan uzundur**, böylece açılan kesici kapanmaz ve yarı açık
geçişi ölçüme karışmaz.

```js
// servisler.mjs — 8302 bildirim (surekli arizali), 8303 katalog (saglikli), 8301 odunc.
// Devre kesici iki yerlesimde de ayni koddur; degisen tek sey durumun hangi anahtarla tutuldugudur.
import { createServer, request } from "node:http";
const s = { katalog: 0, gonder: 0, hatirlat: 0, iptal: 0 };
createServer((i, y) => {                            // 8302 bildirim: her cagride 503
  if (i.url === "/sayac") return y.end(JSON.stringify(s));
  if (i.url === "/sifirla") { for (const k in s) s[k] = 0; return y.end("{}"); }
  s[i.url.slice(1)] += 1; y.statusCode = 503; y.end("{}");
}).listen(8302);
createServer((i, y) => { s.katalog += 1; y.end("{}"); }).listen(8303);

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();
});
let ESIK = 5, durum = new Map();                    // DY7: kesik suresi kosumdan uzun; yari acik gecis M14/K06'da kuruldu
const KESIK = 3_600_000;
const kesici = (a) => { if (!durum.has(a)) durum.set(a, { ardisik: 0, acikBitis: 0 }); return durum.get(a); };
const istek = async (port, yol, anahtar) => {       // kesici burada; anahtar yerlesimi belirler
  const d = kesici(anahtar);
  if (Date.now() < d.acikBitis) return 0;           // acik: cagri hic yapilmaz
  const k = await cagir(port, yol);
  if (k >= 500) { d.ardisik += 1; if (d.ardisik >= ESIK) d.acikBitis = Date.now() + KESIK; } else d.ardisik = 0;
  return k;
};
createServer(async (i, y) => {                      // 8301 odunc: uc cagri yeri ayni bagimliliga gider
  const q = new URL(i.url, "http://x").searchParams;
  if (i.url.startsWith("/kur")) { ESIK = Number(q.get("esik")); durum = new Map(); return y.end("{}"); }
  if (i.url.startsWith("/durum"))
    return y.end(JSON.stringify([...durum].map(([a, d]) => [a, Date.now() < d.acikBitis])));
  const n = Number(q.get("n")), yer = q.get("yer");
  const an = (bagimlilik, cagriYeri) => (yer === "bagimlilik" ? bagimlilik : cagriYeri);
  await istek(8303, "/kitap", an("katalog", "kitap"));
  await istek(8302, "/gonder", an("bildirim", "gonder"));
  await istek(8302, "/hatirlat", an("bildirim", "hatirlat"));
  if (n % 20 === 0) await istek(8302, "/iptal", an("bildirim", "iptal"));
  y.end("{}");
}).listen(8301);
```

`an` işlevi bu dersin tamamıdır. Kesicinin kodu değişmiyor, eşik değişmiyor, çağrı yerleri
değişmiyor; değişen tek şey `istek` çağrısına geçirilen anahtarın bağımlılığı mı yoksa çağrı yerini
mi adlandırdığı. Üç çağrı yerinden ikisi her istekte, `iptal` yolu **her yirmi istekte bir**
çağrılır; gerçek bir kod tabanında sık ve seyrek yollar hep birlikte bulunur.

```js
// olc.mjs — kesicinin durumu nerede tutuluyor: bagimlilik basina mi, cagri yeri basina mi.
import { request } from "node:http";
const N = 60;                                       // 60 kullanici istegi; iptal yolu her 20'de bir cagrilir
const cagir = (port, yol) => new Promise((coz) => {
  const r = request({ port, path: yol, agent: false }, (y) => {
    let g = ""; y.on("data", (p) => (g += p)); y.on("end", () => coz(g));
  });
  r.on("error", () => coz("")); r.end();
});
const yaz = (a, ...r) => console.log(String(a).padEnd(18) + r.map((x) => String(x).padStart(16)).join(""));

const kos = async (esik, yer) => {
  await cagir(8302, "/sifirla");
  await cagir(8301, `/kur?esik=${esik}`);
  for (let n = 1; n <= N; n += 1) await cagir(8301, `/istek?n=${n}&yer=${yer}`);
  const s = JSON.parse(await cagir(8302, "/sayac"));
  const d = JSON.parse(await cagir(8301, "/durum"));
  return { ...s, nesne: d.length, acik: d.filter(([, a]) => a).length };
};

console.log(`${N} kullanici istegi; gonder ve hatirlat her istekte, iptal her 20 istekte bir cagrilir`);
console.log("bildirim bagimliligi kalici arizalidir: her cagriya 503 doner");
yaz("esik / yerlesim", "durum nesnesi", "acik nesne", "bildirim cagri", "gonder", "hatirlat", "iptal", "katalog");
const t = {};
for (const esik of [3, 5, 10])
  for (const [yer, ad] of [["bagimlilik", "bagimlilik"], ["cagriYeri", "cagri yeri"]]) {
    const r = await kos(esik, yer);
    t[`${esik}${yer}`] = r;
    yaz(`${esik} / ${ad}`, r.nesne, r.acik, r.gonder + r.hatirlat + r.iptal, r.gonder, r.hatirlat, r.iptal, r.katalog);
  }
const top = (r) => r.gonder + r.hatirlat + r.iptal;
console.log(`\nyapilandirma yuzeyi: 2 sayi (esik, kesik suresi) ve 1 karar (durumun anahtari).`);
console.log(`ayni esik, iki yerlesimde iki ayri anlam: esik 5 icin bagimliliga giden cagri ` +
  `${top(t["5bagimlilik"])} -> ${top(t["5cagriYeri"])}; esik 10 icin ${top(t["10bagimlilik"])} -> ${top(t["10cagriYeri"])}.`);
console.log(`cagri yeri basina yerlesimde bagimlilik duzeyindeki etkin esik = esik x acilabilen cagri yeri; ` +
  `esik 10'da iptal yolu ${t["10cagriYeri"].iptal} cagriyla esige hic ulasmadi ve kesicisi kapali kaldi.`);
process.exit(0);
```

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

```
60 kullanici istegi; gonder ve hatirlat her istekte, iptal her 20 istekte bir cagrilir
bildirim bagimliligi kalici arizalidir: her cagriya 503 doner
esik / yerlesim      durum nesnesi      acik nesne  bildirim cagri          gonder        hatirlat           iptal         katalog
3 / bagimlilik                   2               1               3               2               1               0              60
3 / cagri yeri                   4               3               9               3               3               3              60
5 / bagimlilik                   2               1               5               3               2               0              60
5 / cagri yeri                   4               2              13               5               5               3              60
10 / bagimlilik                  2               1              10               5               5               0              60
10 / cagri yeri                  4               2              23              10              10               3              60

yapilandirma yuzeyi: 2 sayi (esik, kesik suresi) ve 1 karar (durumun anahtari).
ayni esik, iki yerlesimde iki ayri anlam: esik 5 icin bagimliliga giden cagri 5 -> 13; esik 10 icin 10 -> 23.
cagri yeri basina yerlesimde bagimlilik duzeyindeki etkin esik = esik x acilabilen cagri yeri; esik 10'da iptal yolu 3 cagriyla esige hic ulasmadi ve kesicisi kapali kaldi.
```

## Durum Nesnesi Sütunu

En sol sayısal sütun yerleşimin doğrudan tanımıdır: bağımlılık başına yerleşimde **2 durum
nesnesi**, çağrı yeri başına yerleşimde **4**. İkisi de aynı iki bağımlılığa gidiyor; fark, birinde
durumun bağımlılık sayısınca, ötekinde çağrı yeri sayısınca çoğalmasıdır. Bu sayı kod tabanıyla
birlikte büyür: çağrı yeri eklendiğinde bağımlılık başına yerleşimde hiçbir şey değişmez, çağrı yeri
başına yerleşimde bir durum nesnesi daha doğar ve o nesne sıfırdan öğrenmeye başlar.

Öğrenmenin paylaşılıp paylaşılmadığı **bildirim çağrı** sütununda görünüyor. Eşik 5'te bağımlılık
başına yerleşim bozuk bağımlılığa 5 çağrı yapıyor: `gonder` üç kez, `hatirlat` iki kez başarısız
oluyor, beşinci başarısızlıkta ortak kesici açılıyor ve **`iptal` yolu bağımlılığa hiç gitmiyor** —
sütunda 0. Bir çağrı yerinin öğrendiğini öteki de biliyor.

Çağrı yeri başına yerleşimde aynı eşikle 13 çağrı gidiyor: `gonder` 5, `hatirlat` 5, `iptal` 3. Her
çağrı yeri aynı gerçeği **baştan** öğreniyor. Bağımlılık zaten düşmüşken üçüncü çağrı yeri hiçbir
şey bilmiyormuş gibi davranıyor.

## Aynı Eşiğin İki Ayrı Anlamı

Eşik satırları birlikte okunduğunda yapılandırma yüzeyinin asıl sorunu çıkıyor. Eşik 3, 5 ve 10 için
bağımlılığa giden çağrı bağımlılık başına yerleşimde 3, 5 ve 10; çağrı yeri başına yerleşimde 9, 13
ve 23. **Eşik 5 yazan kişi bir yerleşimde "bağımlılığa en çok beş başarısız çağrı" demiş oluyor,
ötekinde "her çağrı yeri için beş, toplamda on beşe kadar".** Sayı aynıdır, anlamı değildir ve
kodda hangi anlamın geçerli olduğunu söyleyen tek şey bir anahtarın adıdır.

Bağımlılık düzeyindeki etkin eşik, çağrı yeri başına yerleşimde eşik ile açılabilen çağrı yeri
sayısının çarpımıdır. Bu çarpan yapılandırmada hiçbir yerde yazmaz; kaynaktaki çağrı yeri sayısıdır
ve her yeni çağrı yeriyle sessizce büyür.

## Açılmayan Kesici

Son satır bu dersin en sert ölçüsüdür. Eşik 10'da çağrı yeri başına yerleşimde **4 durum nesnesinin
yalnız 2'si açık** — `gonder` ve `hatirlat` açıldı, `iptal` açılmadı. Nedeni aritmetiktir: `iptal`
yolu 60 istekte yalnız 3 kez çağrılıyor ve 3 başarısızlık 10'luk eşiğe hiç ulaşmıyor.

Sonucu şudur: bağımlılık bozuk olduğu **bilindiği hâlde** o çağrı yeri her çağrıldığında yine dışarı
gidiyor. Kesici oradadır, kodu doğrudur, ayarı ötekilerle aynıdır ve hiçbir zaman işe yaramayacaktır.
Seyrek çağrılan bir çağrı yeri kendi başına bir eşiği hiçbir zaman dolduramaz — **korumasız kalan
tam da en az sınanmış yoldur.** Bağımlılık başına yerleşimde aynı yol sıfır çağrı yapıyor, çünkü sık
çağrılan komşularının öğrendiğini devralıyor.

`katalog` sütunu her satırda 60'tır. Kesici sağlıklı bağımlılığa hiç dokunmuyor ve iki yerleşimde de
aynı davranıyor; durum paylaşımı **bağımlılıklar arasında değil, aynı bağımlılığın çağrı yerleri
arasında** bir sorudur.

## Sınanabilirlik

```js
// test/kesici.test.mjs — kesicinin durumu nerede tutuluyorsa iddia oraya baglanir.
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) => {
    let g = ""; y.on("data", (p) => (g += p)); y.on("end", () => coz(g));
  });
  r.on("error", () => coz("")); r.end();
});
const kos = async (esik, yer, n = 60) => {
  await cagir(8302, "/sifirla");
  await cagir(8301, `/kur?esik=${esik}`);
  for (let i = 1; i <= n; i += 1) await cagir(8301, `/istek?n=${i}&yer=${yer}`);
  return { s: JSON.parse(await cagir(8302, "/sayac")), d: JSON.parse(await cagir(8301, "/durum")) };
};

test("bagimlilik basina: bir cagri yerinin ogrendigini oteki de bilir", async () => {
  const { s, d } = await kos(5, "bagimlilik");
  assert.equal(s.iptal, 0);                         // iptal yolu bagimliliga hic gitmedi
  assert.equal(d.length, 2);                        // tek iddia: iki bagimlilik, iki durum nesnesi
});
test("cagri yeri basina: seyrek cagri yeri esige hic ulasmaz", async () => {
  const { s, d } = await kos(10, "cagriYeri");
  assert.equal(s.iptal, 3);                         // bagimlilik bozukken uc kez daha cagrildi
  assert.deepEqual(d.find(([a]) => a === "iptal"), ["iptal", false]);
});
test("kesicinin kapsami bagimlilikla sinirlidir", async () => {
  for (const yer of ["bagimlilik", "cagriYeri"]) assert.equal((await kos(5, yer)).s.katalog, 60);
});
```

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

```
ok 1 - bagimlilik basina: bir cagri yerinin ogrendigini oteki de bilir
ok 2 - cagri yeri basina: seyrek cagri yeri esige hic ulasmaz
ok 3 - kesicinin kapsami bagimlilikla sinirlidir
# tests 3
# pass 3
# fail 0
```

Kesicinin testte tetiklenmesi kolaydır — bağımlılığı bozuk tutmak ve eşik kadar çağrı yapmak yeter.
Zor olan **hangi durumun sınandığıdır.** Bağımlılık başına yerleşimde tek bir nesne vardır ve tek bir
iddia bütün çağrı yerlerini kapsar; birinci testin `d.length` üzerine kurduğu iddia budur. Çağrı
yeri başına yerleşimde her çağrı yerinin kendi durumu ayrı ayrı sınanmalıdır ve ikinci testin
gösterdiği gibi, sınanmayan çağrı yeri sessizce korumasız kalır. Yerleşim yalnız çalışma zamanı
davranışını değil, **testin kaç iddia yazması gerektiğini** de belirliyor: bir bağımlılık için bir,
ya da çağrı yeri sayısınca.

## Özet

- Devre kesicinin durumları M14/K06 Uygulama Mimarisi kursunda, sistem üzerindeki etkisi M19/K05
  Dayanıklılık ve Güvenilirlik kursunda kuruldu; burada ölçülen durumun kodda nerede tutulduğudur.
  İki yerleşim arasındaki fark tek bir anahtarın adıdır.
- Durum nesnesi sayısı yerleşimin doğrudan sonucudur: bağımlılık başına 2, çağrı yeri başına 4.
  Çağrı yeri eklendiğinde ikincisinde bir durum nesnesi daha doğar ve sıfırdan öğrenmeye başlar.
- Aynı eşikte bozuk bağımlılığa giden çağrı 5'e karşı 13'tür; bağımlılık başına yerleşimde bir çağrı
  yerinin öğrendiğini öteki devralır ve `iptal` yolu bağımlılığa hiç gitmez.
- Aynı eşik iki yerleşimde iki ayrı anlam taşır: 3, 5, 10 eşikleri bağımlılıkta 3, 5, 10 çağrıya
  karşılık gelirken çağrı yeri başına yerleşimde 9, 13, 23 çağrıya karşılık gelir. Bağımlılık
  düzeyindeki etkin eşik, eşik ile çağrı yeri sayısının çarpımıdır ve bu çarpan hiçbir yapılandırmada
  yazmaz.
- Seyrek çağrılan yol kendi eşiğini dolduramaz: eşik 10'da `iptal` yolunun kesicisi 3 çağrıyla kapalı
  kaldı ve bağımlılık bozuk olduğu bilindiği hâlde her çağrıda dışarı gitmeyi sürdürdü.
- Kesici sağlıklı bağımlılığa dokunmaz (katalog her satırda 60); paylaşım sorusu bağımlılıklar
  arasında değil, aynı bağımlılığın çağrı yerleri arasındadır. Testte bağımlılık başına yerleşim tek
  iddiayla kapanır, çağrı yeri başına yerleşim çağrı yeri sayısınca iddia ister.

## Sonraki Adım

Kesici bir sınır çizdi ama sınırın malzemesi bilgidir: koruma ancak yeterince başarısızlık
biriktikten sonra başlıyor ve seyrek yollarda hiç başlamıyor. Dahası kesici bir bağımlılığın bozuk
olduğunu anlar, o bağımlılığı çağıran işin çağıranın kaynaklarını tükettiğini anlamaz — üç çağrı
yeri de aynı süreçte, aynı havuzdan çalışıyor ve biri yavaşladığında ötekilere kalan pay küçülüyor.
O hâlde bir soru daha vardır: bulaşmayı algılamaya hiç bağlamadan, baştan kesmek mümkün müdür.
Sonraki ders kaynak havuzunu bölerek bunu dener ve havuzun kodda nerede tanımlandığını, bir
bağımlılığı kendi havuzuna almanın kaç çağrı yerine dokunduğunu, havuz sınırının hangi yollardan
atlandığını ve yanlış boyutlandırmanın hangi davranışı ürettiğini ölçer.
