---
title: 'Alt Süreçler'
source: 'https://academia.sh/tr/kurslar/nodejs/alt-surecler'
course: 'Node.js Çalışma Zamanı'
language: tr
updated: '2026-08-17T18:09:51+00:00'
license: 'CC BY-SA 4.0'
---

# Alt Süreçler

Dış komut çalıştırmanın iki yolu, kabuk katmanının getirdiği risk, çıkış kodu ile sonlandıran sinyalin ayrımı ve çalışma zamanı süreçleri arasında ileti geçirme.

Önceki ders hizmeti tek bir süreçte kurdu. Bir sürecin yapabileceği iş sınırlıdır ve
bazı işleri hiç yapmaması gerekir: sistemde zaten var olan bir aracın işini yeniden
yazmak, o aracın yıllarca sınanmış davranışını yeniden üretmeye çalışmaktır.

Bu ders sürecin dışına iş çıkarmayı ele alır. İki ayrı ihtiyaç vardır: bir dış komutu
çalıştırmak ve aynı çalışma zamanından ikinci bir süreç başlatıp onunla konuşmak.

## Dış Komut Çalıştırmak

`node:child_process` modülündeki `spawn`, bir programı ayrı süreç olarak başlatır ve
onun üç standart akışını nesne olarak verir. Kabuk Programlama kursundaki akış modeli
burada olduğu gibi karşılık bulur.

```js
// alt-surec.mjs
import { spawn } from 'node:child_process';
import { once } from 'node:events';

function calistir(komut, argumanlar) {
  const cocuk = spawn(komut, argumanlar);      // kabuk yok: argumanlar dizi olarak gecer
  const cikti = [];
  const hata = [];
  cocuk.stdout.on('data', (p) => cikti.push(p));
  cocuk.stderr.on('data', (p) => hata.push(p));
  return once(cocuk, 'close').then(([kod, sinyal]) => ({
    kod,
    sinyal,
    cikti: Buffer.concat(cikti).toString('utf8').trim(),
    hata: Buffer.concat(hata).toString('utf8').trim(),
  }));
}

console.log('wc -l  :', await calistir('wc', ['-l', 'olcumler.ndjson']));
console.log('yok.txt:', await calistir('cat', ['yok.txt']));
```

```sh
node alt-surec.mjs
```

```
wc -l  : { kod: 0, sinyal: null, cikti: '12 olcumler.ndjson', hata: '' }
yok.txt: {
  kod: 1,
  sinyal: null,
  cikti: '',
  hata: 'cat: yok.txt: No such file or directory'
}
```

İki çağrının ayrımı çıkış kodundadır. Sıfır başarıyı, bir başarısızlığı bildirir;
Kabuk Programlama kursundaki kural değişmedi. Tanı iletisi ikinci akıştan geldi ve
veriyle karışmadı — aynı ayrımın çalışma zamanı tarafındaki karşılığı budur.

Parçalar arabellek olarak toplanıp sonda birleştiriliyor. Her parçayı ayrı ayrı
dizgiye çevirip eklemek, arabellekler dersinde gösterilen sınır bozulmasına yol
açardı.

## Kabuk Katmanı ve Argüman Aktarımı

Aynı modülde `exec` adlı bir fonksiyon daha vardır. Fark, komutu bir kabuk sürecine metin
olarak vermesidir. Kabuk o metni kendi kurallarıyla yorumlar: değişken açılımı,
yol adı genişletmesi, boru hattı, noktalı virgülle komut ayırma.

Bu yorum, komut metnine dışarıdan gelen bir parça eklendiğinde sorun olur:

```js
// alt-surec-kabuk.mjs
import { execFile, exec } from 'node:child_process';
import { promisify } from 'node:util';

const execSoz = promisify(exec);
const execFileSoz = promisify(execFile);

// Disaridan gelmis, guvenilmeyen bir dosya adi
const dosyaAdi = 'olcumler.ndjson; echo ENJEKTE';

// 1. Kabugu araya sokan cagri: metin kabuk tarafindan yorumlanir
const { stdout: kabukCiktisi } = await execSoz(`wc -l ${dosyaAdi}`);
console.log('exec     :', JSON.stringify(kabukCiktisi.trim()));

// 2. Kabuk olmadan cagri: ad tek bir arguman olarak gecer
try {
  await execFileSoz('wc', ['-l', dosyaAdi]);
} catch (hata) {
  console.log('execFile :', hata.stderr.trim());
}
```

```sh
node alt-surec-kabuk.mjs
```

```
exec     : "12 olcumler.ndjson\nENJEKTE"
execFile : wc: olcumler.ndjson; echo ENJEKTE: open: No such file or directory
```

Birinci çağrıda noktalı virgülden sonraki komut da çalıştı. Dosya adı yerine
gelen metin bir hesap silme ya da veri gönderme komutu olsaydı sonuç aynı biçimde
çalıştırılırdı. İkinci çağrıda ise metnin tamamı tek bir argüman olarak geçti; `wc`
o adda bir dosya arayıp bulamadı.

Kural: **komut metnini dizgi birleştirmesiyle kurmayın.** Program adı ve argüman
dizisi ayrı verildiğinde araya kabuk girmez ve yorumlanacak bir metin oluşmaz.
Gerçekten kabuk özelliği gerekiyorsa — boru hattı veya yönlendirme gibi — sabit bir
komut metni yazılır ve değişken bölümler ortam değişkeni olarak aktarılır.

`promisify`, geri çağrılı imzayı söz döndüren imzaya çeviren yerleşik yardımcıdır.
Çalışma zamanının geri çağrılı arayüzlerinin çoğu bu dönüşümü destekler.

`exec` ve `execFile` ayrıca çıktıyı bellekte biriktirir ve bir sınırı aştığında
süreci sonlandırır. Büyük çıktı üreten komutlarda `spawn` kullanılır ve çıktı akışla
işlenir.

## Çıkış Kodu ve Sonlandıran Sinyal

Bir alt sürecin bitişi iki farklı yolla olabilir: kendi isteğiyle çıkarak veya bir
sinyalle sonlandırılarak. `close` olayı bu iki durumu ayrı alanlarda bildirir.

```js
// alt-surec-sinyal.mjs
import { spawn } from 'node:child_process';
import { once } from 'node:events';

// Uzun surecek bir is; kendiliginden bitmesini beklemeyecegiz
const cocuk = spawn('sleep', ['30']);
console.log('cocuk baslatildi, ayri surec mi:', cocuk.pid !== process.pid);

setTimeout(() => cocuk.kill('SIGTERM'), 100);

const [kod, sinyal] = await once(cocuk, 'close');
console.log('cikis kodu:', kod, '| sonlandiran sinyal:', sinyal);
```

```sh
node alt-surec-sinyal.mjs
```

```
cocuk baslatildi, ayri surec mi: true
cikis kodu: null | sonlandiran sinyal: SIGTERM
```

Sinyalle sonlandırılan bir sürecin çıkış kodu yoktur; alan `null` gelir. Yalnızca
koda bakan bir denetim, `kod === 0` sınamasını geçemez ama `kod !== 0` sınamasını da
farklı yorumlayabilir. Doğru denetim iki alanı birlikte okur: kod sıfırsa **ve**
sinyal yoksa başarı.

Sinyal adının kendisi Kabuk Programlama kursunda tanıtılmıştı; `SIGTERM` kibar bir
sonlanma isteğidir ve süreç onu yakalayıp temizlik yapabilir. Zorla sonlandıran
sinyal yakalanamaz ve temizliğe fırsat vermez; bu yüzden yalnızca kibar istek
yanıtsız kaldığında kullanılır. Sürecin kendi kapanma davranışı Süreç Yönetimi ve
Sağlamlık dersinin konusudur.

## Aynı Çalışma Zamanından İkinci Süreç

Ölçüm toplayıcının pahalı işi kendi kodudur, dış bir araç değil. Bunun için `fork`
kullanılır: aynı çalışma zamanının yeni bir örneğini başlatır ve iki süreç arasında
bir ileti kanalı kurar.

```js
// ozet-cocuk.mjs
import { readFile } from 'node:fs/promises';

process.on('message', async ({ dosya }) => {
  const metin = await readFile(dosya, 'utf8');
  const kovalar = new Map();
  for (const satir of metin.split('\n')) {
    if (satir.trim() === '') continue;
    const { dugum, metrik, deger } = JSON.parse(satir);
    const anahtar = `${dugum}/${metrik}`;
    const kova = kovalar.get(anahtar) ?? { sayi: 0, toplam: 0 };
    kova.sayi += 1;
    kova.toplam += deger;
    kovalar.set(anahtar, kova);
  }
  process.send({ pidVar: typeof process.pid === 'number', kovaSayisi: kovalar.size });
  process.disconnect();
});
```

```js
// ozet-ana.mjs
import { fork } from 'node:child_process';
import { once } from 'node:events';

const cocuk = fork('./ozet-cocuk.mjs');
console.log('ayri surec mi:', cocuk.pid !== process.pid);

cocuk.send({ dosya: 'olcumler.ndjson' });
const [ileti] = await once(cocuk, 'message');
console.log('cocuktan gelen:', ileti);

const [kod] = await once(cocuk, 'exit');
console.log('cocuk cikis kodu:', kod);
```

```sh
node ozet-ana.mjs
```

```
ayri surec mi: true
cocuktan gelen: { pidVar: true, kovaSayisi: 6 }
cocuk cikis kodu: 0
```

İki süreç arasında hiçbir bellek paylaşılmaz. `send` ile verilen değer dizileştirilip
kanaldan geçirilir ve karşı tarafta yeniden kurulur; dolayısıyla yalnızca
dizileştirilebilir değerler taşınabilir — fonksiyon, sınıf örneği ve dosya tanıtıcısı
doğrudan geçmez. Bu kopyalama, büyük veri için ölçülebilir bir maliyettir: çocuğa
milyonlarca kayıt göndermek yerine, dosya adını gönderip okumayı ona bırakmak
tercih edilir. Yukarıdaki örnek tam olarak bunu yapıyor.

`disconnect` çağrısı kanalı kapatır. Kanal açık kaldığı sürece iki süreç de birbirini
ayakta tutar; çocuk işini bitirdiği hâlde çıkmıyorsa nedeni genellikle budur.

Yalıtımın bir yararı daha vardır: çocuk sürecin çökmesi ana süreci düşürmez. Ana
süreç `exit` olayını görür, kararı kendisi verir — yeniden başlatabilir, isteği
hatayla yanıtlayabilir veya işi kendi yapabilir.

## Özet

- `spawn`, programı ayrı süreç olarak başlatır ve üç standart akışını nesne olarak
  verir; büyük çıktı akışla işlenir.
- Kabuk üzerinden çalıştırma, komut metnini yorumlar; metne dışarıdan gelen bir parça
  eklendiğinde ek komut çalıştırılabilir. Program adı ve argüman dizisi ayrı verilir.
- Çıkış kodu ile sonlandıran sinyal ayrı alanlardır; sinyalle sonlandırılan sürecin
  kodu yoktur ve başarı denetimi iki alanı birlikte okur.
- `fork`, aynı çalışma zamanının ikinci örneğini başlatır ve ileti kanalı kurar;
  iletiler dizileştirilerek kopyalanır, bellek paylaşılmaz.
- Süreç yalıtımı, çocuğun çökmesini ana sürecin kararına dönüştürür.

## Sonraki Adım

Alt süreç, işi ana iş parçacığından çıkarmanın bir yoludur ama ağır bir yoludur:
her süreç kendi belleğini ve kendi çalışma zamanı örneğini taşır, aralarındaki her
ileti kopyalanır. Sonraki ders iki alternatifi ele alır — aynı bağlantı noktasını
paylaşan süreç kümesi ve aynı süreç içinde bellek paylaşabilen iş parçacıkları — ve
hangisinin hangi iş türüne uygun olduğunu belirler.
