---
title: Dağıtım
source: 'https://academia.sh/tr/kurslar/ruby-uretim/dagitim'
course: 'Ruby Ekosistemi ve Üretim'
language: tr
updated: '2026-10-21T05:03:44+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Varlık adının içerik özetinden geldiğini ve belirleyeninin kod olduğunu ölçer'
    - 'Sürüm dizini adının saatten geldiğini ve belirleyeninin ortam olduğunu gösterir'
    - 'Sembolik bağla atomik geçişi ve geri almayı geçici bir dizinde sınar'
    - 'Aynı yayının üç parçasının üç ayrı belirleyeni olduğunu açıklar'
---

# Dağıtım

Üretime çıkan yayının içinde ne olduğu üç ayrı soruyla sorulur. Ders varlık adını, sürüm dizinini ve yayın bildirimini ayrı ayrı ölçer, sembolik bağla atomik geçişi ve geri almayı sınar ve kursun dokuz ölçümünü tek tabloda toplar.

Önceki ders sıcak yolun çağrı sayısından, sürenin ise ortamdan geldiğini gösterdi. Elde ölçülmüş, test edilmiş, paketlenmiş bir uygulama var; geriye üretime çıkarmak kalıyor. Bu da kursun ölçü eksenine bağlanır: **bu sonucu ne belirliyor?** Üretime çıkan şey tek bir nesne değildir. Bir yayının üç parçası vardır ve her birinin belirleyeni farklıdır.

**Dağıtım (deployment)**, yayını hedef makineye taşıyıp yürürlüğe koyma işidir. M12/K05'te dağıtımın aşamaları ve araçları görülmüştü; bu ders aşamaları yinelemez, yayının içindeki üç değerin ne ürettiğini ölçer. Çekirdeğin `belirleyen.rb` dosyası ve bu dersin kesiti `dagitim.rb` aşağıda olduğu gibi verilir; ikisi de kaynaktır, çıktısı yoktur. Çekirdek bir modeldir: saat, çekirdek sayısı ve kilit dosyasının içeriği tanımdan gelir.

```ruby
# belirleyen.rb — bir kosum modeli ve bir sonucu neyin belirledigini siniflandiran yardimci

# Kosum: sonucun bagli olabilecegi uc girdi. Bu uc girdinin disinda kalan her sey koddur.
Kosum = Data.define(:kilit, :tohum, :ortam)

TABAN = Kosum.new(
  kilit: { "bicimleyici" => "1.4.2", "ayristirici" => "2.0.1" },
  tohum: 1,
  ortam: { saat: Time.utc(2026, 10, 16, 9, 0), cekirdek: 4, degiskenler: {} }
)

# Her degisken tek bir girdiyi degistirir; otekiler tabandaki gibi kalir.
DEGISKENLER = {
  bagimlilik: TABAN.with(kilit: { "bicimleyici" => "1.5.0", "ayristirici" => "2.1.0" }),
  sira: TABAN.with(tohum: 2),
  ortam: TABAN.with(ortam: { saat: Time.utc(2027, 3, 1, 9, 0), cekirdek: 8,
                             degiskenler: { "ISCI_SAYISI" => "3" } })
}

# Kural: hesap once tabanda, sonra her degiskende bir kez kosar. Sonucu degistiren ilk
# degisken (bagimlilik, sira, ortam sirasiyla) belirleyendir; hicbiri degistirmiyorsa kod.
def belirleyen(hesap)
  taban = hesap.call(TABAN)
  degisti = DEGISKENLER.to_h { |ad, kosum| [ad, hesap.call(kosum) != taban] }
  tur = degisti.key(true)&.to_s || "kod"
  kanit = degisti.map { |ad, d| "#{ad[0].upcase}#{d ? '+' : '-'}" }.join(" ")
  [tur, kanit, taban]
end
```

```ruby
# dagitim.rb — varlik adi icerigin ozetini tasir; yayina kilitteki surumler kurulur
require "digest"

# Dagitim: varlik adi icerigin ozetini tasir; yayina kilitteki surumler kurulur.
def varlik_adi(ad, icerik) = ad.sub(/(\.\w+)\z/) { "-#{Digest::SHA256.hexdigest(icerik)[0, 8]}#{Regexp.last_match(1)}" }

def yayin_bildirimi(kosum)
  [varlik_adi("uygulama.css", "body { margin: 0 }"), *kosum.kilit.map { |ad, s| "#{ad}-#{s}" }]
end
```

## Varlık Adı İçeriğin Özetinden Gelir

Üretimde bir stil dosyası ya da betik, adında içeriğinin **içerik özeti (digest)** ile yayımlanır. İçerik değişince ad değişir ve tarayıcıdaki eski kopya kendiliğinden geçersiz olur. `varlik_adi` içeriğin SHA-256 özetinin ilk sekiz karakterini dosya adının uzantısından önce ekler. Aşağıdaki blok aynı dosya adını iki ayrı içerikle çağırır ve kuralı çalıştırır.

```ruby
# varlik.rb — varlik adi icerige baglidir
require_relative "belirleyen"
require_relative "dagitim"

puts varlik_adi("uygulama.css", "body { margin: 0 }")
puts varlik_adi("uygulama.css", "body { margin: 1px }")
p belirleyen(->(_k) { varlik_adi("uygulama.css", "body { margin: 0 }") })
```

```
uygulama-997facec.css
uygulama-42043fc8.css
["kod", "B- S- O-", "uygulama-997facec.css"]
```

İçerikteki `0` yerine `1px` yazılınca ad değişti. Kural üç değişkenin hiçbirinde farklı bir ad görmedi: kilit dosyasının sürümleri, tohum ve ortam adı etkilemedi. Belirleyen **kod**dur; ad, içeriğin özetinden gelir ve içerik kodun parçasıdır. **RB17.** Özetin ilk sekiz karakteri çakışma olasılığını sıfırlamaz; bu ölçüm iki içerik için ayrı ad gösterir ve herhangi iki içerik için ayrı ad garantisi vermez.

## Sürüm Dizini Saatten Gelir

Her yayın hedef makinede kendi dizinine konur, ad olarak yayının saatini taşır. Böylece eski yayın silinmeden yanında durur. Dizin adı saatten kurulur ve saat modelde ortamın bir girdisidir.

```ruby
# surum.rb — surum dizini saatten kurulur
require_relative "belirleyen"

surum_dizini = ->(saat) { "surumler/#{saat.strftime('%Y%m%d%H%M%S')}" }
p belirleyen(->(k) { surum_dizini.call(k.ortam[:saat]) })
```

```
["ortam", "B- S- O+", "surumler/20261016090000"]
```

Tabanın saati 16 Ekim 2026, dokuz sıfır sıfırdır ve dizin adı bu zamanı taşır. Kural bu hesabı üç değişkende koşturdu: yalnız ortamın saati farklıydı, sonuç değişti. Kanıt `B- S- O+`, belirleyen **ortam**dır. Hesap deterministik bir işlemdir, ama girdisi saattir ve saat dışarıdan gelir. **RB18.** Gerçek saat bu ölçümde kullanılmadı; çekirdeğin sabit saati kullanıldı ve gerçek bir dağıtımda ad her yayında farklı olur.

## Bildirim Kilitteki Sürümleri Taşır

Yayın bildirimi, yayının hangi varlık adını ve hangi paket sürümlerini içerdiğini söyler. Varlık adı koddan gelir; paket sürümleri kilit dosyasından.

```ruby
# bildirim.rb — yayin bildirimi kilitteki surumleri tasir
require_relative "belirleyen"
require_relative "dagitim"

p yayin_bildirimi(DEGISKENLER[:bagimlilik])
p belirleyen(->(k) { yayin_bildirimi(k) })
```

```
["uygulama-997facec.css", "bicimleyici-1.5.0", "ayristirici-2.1.0"]
["bagimlilik", "B+ S- O-", ["uygulama-997facec.css", "bicimleyici-1.4.2", "ayristirici-2.0.1"]]
```

Birinci satır, kilidi `1.5.0` ve `2.1.0` olan değişkenin bildirimidir: varlık adı aynı kalır, paket sürümleri değişir. İkinci satır kuralı çalıştırır. Kural kilit değişkeninde farkı görür ve belirleyen **bağımlılık**tır. Aynı bildirimde varlık adı koddan gelir, ama kural ilk değiştiren belirleyeni verir ve değiştiren bağımlılık olunca kod ikinci planda kalır. Kanıt `B+ S- O-`. **RB19.** Kural tek bir belirleyen verir; birden çok girdi aynı anda değişirse sıradaki ilk değiştiren seçilir ve diğerleri kanıt sütununda görünür.

## Sembolik Bağ, Atomik Geçiş ve Geri Alma

Yeni yayın hazırlanınca yürürlükteki yayın bir **sembolik bağ (symlink)** ile gösterilir; geçiş, bağın bir adımda değiştirilmesidir. Bunu geçici bir dizinde sınayalım: iki sürüm dizini, bir bağ, atomik geçiş ve geri alma. Bağ önce geçici bir adla kurulur, sonra `File.rename` ile asıl ada taşınır; yeniden adlandırma tek adımdır, bu yüzden aradaki hiçbir anda bağ yok değildir.

```ruby
# gecis.rb — sembolik bagla atomik gecis ve geri alma
require "tmpdir"

def bagla(hedef)
  File.symlink(hedef, "gecerli.gecici")
  File.rename("gecerli.gecici", "gecerli")
end

Dir.mktmpdir do |dizin|
  Dir.chdir(dizin) do
    Dir.mkdir("surumler")
    Dir.mkdir("surumler/20261016090000")
    Dir.mkdir("surumler/20261016100000")
    bagla("surumler/20261016090000")
    puts File.readlink("gecerli").split("/").last
    bagla("surumler/20261016100000")
    puts File.readlink("gecerli").split("/").last
    bagla("surumler/20261016090000")
    puts File.readlink("gecerli").split("/").last
  end
end
```

```
20261016090000
20261016100000
20261016090000
```

Bağ önce dokuz sıfır sıfır sürümünü, sonra on sıfır sıfır sürümünü gösterdi; geri alma ise yeni bir bağ kurup dokuz sıfır sıfıra döndü. Geri almak eski dizini yeniden yaratmak değildir; eski dizin hiç silinmediği için yalnız bağ değiştirilir. Geçişten önce bir **sağlık denetimi (health check)** yeni yayının yanıt verdiğine bakar ve karar verir: iki istek de başarılıysa geç, biri başarısızsa geri al.

```ruby
# saglik.rb — saglik denetimi gecis ya da geri alma kararini verir
karar = ->(kodlar) { kodlar.all?(200) ? "gecis" : "geri al" }
puts karar.call([200, 200])
puts karar.call([200, 503])
```

```
gecis
geri al
```

İki istek de iki yüzlük dönünce karar geçiş, biri beş yüz üç dönünce geri almadır. **RB20.** Dizin ve bağ bir geçici dizinde ve tek süreçte sınandı; ağ üzerinden gelen istekler ve eşzamanlı okuyan süreçler bu ölçümde yoktur. **Kesintisiz dağıtım (zero-downtime deployment)** için gereken ek düzenek bu derste ölçülmedi.

## Sınırlayıcı Ölçüm

Aynı yayının üç parçası, üç ayrı soruya üç ayrı yanıt verdi. Aşağıdaki blok bu üçünü aynı anda sorar.

```ruby
# yayin.rb — ayni yayinin uc parcasi, uc belirleyen
require_relative "belirleyen"
require_relative "dagitim"

adlar = {
  "varlik adi" => ->(_k) { varlik_adi("uygulama.css", "body { margin: 0 }") },
  "surum dizini" => ->(k) { "surumler/#{k.ortam[:saat].strftime('%Y%m%d%H%M%S')}" },
  "bildirim" => ->(k) { yayin_bildirimi(k) }
}
adlar.each { |ad, hesap| puts "#{ad}: #{belirleyen(hesap).first}" }
```

```
varlik adi: kod
surum dizini: ortam
bildirim: bagimlilik
```

Varlık adını kod belirler, sürüm dizinini ortam, bildirimi bağımlılık. Üçü aynı yayına aittir; bir yayını tek bir belirleyene bağlamak yanlıştır. Bildirimde ise kural kod değil bağımlılığı verdi: bildirim hem kodun hem kilidin ürünü olsa da `belirleyen` ilk değişen girdiyi seçer ve kilit, kuralda kodun önündedir. Bu dersin gözlemi `yayin bildirimi` satırıdır ve belirleyeni **bağımlılık**tır.

## Özet

- Varlık adını içeriğin özeti belirler; içerik koddan geldiği için belirleyen **kod**dur.
- Sürüm dizininin adı saatten gelir; belirleyen **ortam**dır.
- Yayın bildirimi kilitteki sürümleri taşır; belirleyen **bağımlılık**tır ve kanıtı `B+ S- O-`dir.
- Sembolik bağ ve `File.rename` geçişi atomik yapar; geri alma eski dizini silmeden yeni bir bağ kurmaktır.
- Aynı yayının üç parçası üç ayrı belirleyene sahiptir.

## Kurs Kapanışı

Kursun her dersi aynı soruyu sordu: bu sonucu ne belirliyor. Tablo dokuz dersin ölçtüğü değeri, o dersin belirleyenini ve sınırlayıcı ölçümünün söylediği şeyi yan yana koyar. Belirleyen sütunu her dersin `## Özet` bölümünde yazılı olandır.

| Ders | Ölçülen değer | Belirleyen | Sınırlayıcı ölçüm |
|---|---|---|---|
| Gem Yapısı | paket dosya adı `olcer-0.3.0.gem` | kod | dosya listesini çalışma dizininden toplayan tanımda `[]` ile `["lib/olcer.rb"]` ikisinde de kod |
| Bağımlılık Yönetimi | kilitli sürüm `1.4.2` | bağımlılık | `~> 1.4.0` ile 1.5.0 kilidi `ArgumentError` verir; kural hata veren hesabı sınıflandırmaz |
| Test Çerçeveleri | test sonucu `[]` | sıra | her test `ayar.dup` kullanınca sonuç `["kod", "B- S- O-", []]` |
| Sahteleme ve Test Verisi | saati okuyan test `true` | ortam | tohumlu veri `["sira", "B- S+ O-", [37, 12, 72]]` |
| Eşzamanlılık Modeli | kilitsiz sayaç `6` | sıra | Ractor paylaşılan durumu kaldırır; dondurma yüzeysel kalır |
| Süreç Tabanlı Ölçekleme | işçi sayısı `4` | ortam | çocuk süreçteki dilim toplamı `["kod", "B- S- O-", 155]` |
| Bellek Yönetimi | ayrılan nesne `1001` | kod | ilk koşum ısınma payı taşır |
| Profil Çıkarma | sıcak yol `[:para_bicimle, 200]` | kod | süre ortamdır, çağrı sayısı koddur |
| Dağıtım | yayın bildirimi | bağımlılık | aynı yayının üç parçası üç belirleyen |

Dokuz dersin belirleyen dağılımı: **3 kod · 2 bağımlılık · 2 sıra · 2 ortam**. Bu, çekirdeğin dokuz gözleminin dağılımıyla aynıdır, çünkü çekirdek her ders için bir gözlem taşır. İki sonuç tablodan okunur. Birincisi, aynı koda bakan iki ders bile farklı belirleyen verebilir: kilitsiz sayaç sıraya, işçi sayısı ortama bağlıdır. İkincisi, sınırlayıcı ölçümlerin çoğu dersin belirleyeninin yanında başka bir belirleyenin de çalıştığını gösterdi; bir yayın, bir test ya da bir ölçüm tek bir kaynağa bağlanmaz. **RB21.** Tablo bu kursun dokuz gözleminin dağılımını verir; Ruby uygulamalarının tamamının dağılımı hakkında bir iddia taşımaz.

Kurs burada kapanır ve M13 de onunla kapanır. Müfredat dört soru sordu. Birincisi, bu iletiyi kim yanıtlıyor. İkincisi, bu yöntemi kim yazdı. Üçüncüsü, bu değer hangi isteğe kadar kalıyor. Dördüncüsü, bu sonucu ne belirliyor. Her soru bir önceki sorunun bıraktığı boşluğa girdi: yanıtlayanı bulmak yazanı, yazanı bulmak kalışı, kalışı bulmak ise sonucun kaynağını sormayı gerektirdi. Bu kurs sonuncusunu yalnız ölçerek yanıtladı; bir sonucun neden belirli bir kaynağa bağlandığı sorusu ölçümün ötesinde kaldı.
