Çoğu satıcı stok sorununu bir sayım hatası sanır. "Panelde 4 adet yazıyordu, 5 kişiye gitti, demek ki yükleme sırasında bir satır fazla girmişim" der ve dosyayı yeniden kontrol eder. Oysa dosya doğrudur. Olan şey şudur: iki müşteri neredeyse aynı anda satın al düğmesine bastı, iki ayrı PHP süreci aynı stok satırını okudu, ikisi de "bu kod boşta" gördü ve ikisi de aynı kodu teslim etti. Kimse hata yapmadı; sistem sadece aynı anda iki kişinin aynı şeye uzanabileceğini varsaymamıştı.
Bu duruma yarış koşulu denir ve tek çözümü sıraya sokmaktır. Ama sıra tutmak sandığın kadar basit değil, çünkü modern kurulumlarda aynı e-pin scripti tek bir süreçte değil; birden fazla PHP-FPM işçisinde, bazen birden fazla sunucuda, üstüne bir de kuyruk işçilerinde çalışır. Tek bir süreç içinde tuttuğun bayrak diğer süreçleri hiç görmez. İşte tam bu yüzden ihtiyacın olan şey yerel bir bayrak değil, tüm süreçlerin saygı duyduğu ortak bir otorite: dağıtık kilit.
Neden kodundaki "if" kontrolü seni kurtarmıyor?
Klasik akış şöyledir: stoktan boş kod seç, teslim edilebilir mi diye kontrol et, müşteriye gönder, satırı kullanıldı olarak işaretle. Bu dört adım tek başına okunduğunda kusursuz görünür. Sorun adımların arasındaki boşluktur. İlk süreç kodu seçip henüz işaretlemeden, ikinci süreç aynı seçimi yapabilir. Aradaki süre bazen 10 milisaniyedir, bazen veritabanı yavaşladığında 200 milisaniye. Trafik arttıkça bu boşluğa denk gelme olasılığı doğrusal değil, katlanarak büyür. Dolayısıyla "bende hiç olmadı" demek korumanın var olduğu anlamına gelmez; sadece henüz yeterince aynı anda müşteri gelmediği anlamına gelir. Sağlam bir dijital ürün satış scripti bu boşluğu kapatmak için kararı koddan alıp paylaşılan bir kaynağa devreder.
Kilidi nereye koyacaksın: dosya, veritabanı yoksa Redis mi?
Üç yaygın seçenek var ve her birinin kendi yeri var. Dosya kilidi tek sunucuda çalışır, kurulum gerektirmez ama ikinci sunucu eklediğin gün sessizce işlevsiz kalır. Veritabanı kilidi (MySQL tarafında adlandırılmış kilitler ya da satır kilitleri) zaten kullandığın altyapıyı kullanır, işlem bütünlüğüyle aynı yerde durur ve çoğu satıcı için fazlasıyla yeterlidir. Redis kilidi en hızlısıdır, süre sınırı yerleşiktir ve çok sunuculu kurulumda doğal seçimdir; karşılığında bir servis daha bakmak zorundasın. Kritik nokta teknoloji seçimi değil, kilidin kapsamı: tüm teslimat sürecini değil, tek bir ürünün tek bir stok satırını kilitlemelisin. Aksi halde yavaşlayan bir kod tüm mağazayı bekletir.
| Yöntem | Çok sunucu | Otomatik süre sınırı | Kurulum yükü | Uygun senaryo |
|---|---|---|---|---|
| Dosya kilidi (flock) | Hayır | Hayır | Yok | Tek sunuculu küçük mağaza |
| MySQL adlandırılmış kilit | Evet (aynı DB) | Evet (timeout) | Düşük | Paylaşımlı hostingde standart çözüm |
| Satır kilidi (FOR UPDATE) | Evet | İşlem süresince | Düşük | Stok satırı seçimi |
| Redis kilidi | Evet | Evet (TTL) | Orta | Yüksek trafik, çok işçi |
| Kuyruk ile tek işçi | Evet | Dolaylı | Orta | Toptan/bayi teslimatları |
Kilidin süresini yanlış ayarlarsan ne olur?
Kilit almanın en tehlikeli yanı, onu bırakmayı unutmaktır. Teslimat sırasında sağlayıcı API'si yanıt vermezse ve kilidin süre sınırı yoksa, o ürün sonsuza kadar satılamaz hale gelir. Müşteriler "stok var ama alamıyorum" der, sen sebebini panelde göremezsin. Bu yüzden her kilit mutlaka bir ömürle doğmalı. Ömrü seçerken ölçüt şudur: en yavaş normal teslimatın ne kadar sürüyor? Eğer dış API en kötü durumda 3 saniyede dönüyorsa, kilit ömrünü 5-8 saniye yap. Uzun süren işlerde ise kilidi tutarken yenileme yap; işini bitirmeyen süreç kilidi periyodik olarak tazeler, çöken süreç ise tazelemeyi bırakır ve kilit kendiliğinden serbest kalır. Bu detay, e-pin satış yazılımı ile amatör bir betik arasındaki gerçek farktır.
Yarış koşulunun tetiklendiği noktalar
- Stok satırı seçimi 50%
- Bakiye düşme adımı 25%
- Kuyruk işçisi tekrarı 15%
- Yönetici elle teslimatı 10%
Kilit almak yeterli mi, yoksa stok seçimini de değiştirmen mi gerekiyor?
Deneyimli geliştiricilerin sevdiği bir kısayol var: kilit kurmak yerine seçimi atomik hale getirmek. Yani "boş kodu bul" ve "kullanıldı işaretle" adımlarını tek bir güncelleme ifadesine indirmek. Veritabanına "durumu boşta olan bir satırı bu sipariş numarasıyla işaretle, kaç satır etkilendiğini bana söyle" dersin. Bir satır etkilenmişse kod senin; sıfır satır etkilenmişse başka biri önce davranmış ve müşteriye dürüstçe "stok tükendi" demen gerekir. Bu yaklaşım kilit yükünü tamamen ortadan kaldırır ve çok yüksek trafikte kilitten daha iyi ölçeklenir. Ancak teslimat sırasında birden fazla tabloya dokunuyorsan (stok, sipariş, bakiye, log) yine bir işlem sınırına ve büyük olasılıkla kilide ihtiyacın olur. En sağlıklı kurgu ikisinin birleşimidir: atomik seçim + dar kapsamlı kilit.
Kuyruk işçileri kilidi nasıl deliyor?
Çift teslimatın en az konuşulan kaynağı arka plan işleridir. Ödeme onaylandığında bir teslimat işi kuyruğa atılır. İş bir hata alır, kuyruk onu tekrar dener. Ama ilk deneme aslında teslimatı tamamlamış, sadece bildirim maili gönderilirken hata almıştır. Tekrar denemede aynı iş baştan koşar ve ikinci kod gider. Bu yüzden kuyruk işlerinin ilk satırı her zaman şu olmalı: bu sipariş zaten teslim edildi mi? Kontrolü de kilit altında ya da atomik güncellemeyle yap. İşi yeniden çalıştırılabilir tasarlamak, kuyruk kullanan her epin yazılım kurulumunun temel şartıdır; aksi halde her geçici ağ hatası bir stok kaybına dönüşür.
Kilit adını stock:urun_id:varyant gibi dar bir anahtarla üret. "teslimat" gibi tek bir genel kilit adı kullanırsan bir ürünün yavaşlığı tüm mağazanın satışını sıraya sokar ve kampanya günü tam olarak bu yüzden site kilitlenir.
Kilidin çalıştığını nasıl kanıtlarsın?
Kilit görünmez bir koruma olduğu için varlığını ölçmek gerekir. En hızlı yöntem, tek stoklu bir test ürünü açıp aynı anda yirmi istek göndermektir. Doğru kurulmuş bir sistemde bir müşteri kodu alır, on dokuz müşteri "stok tükendi" görür ve hiçbir kod iki kez görünmez. Ardından kilit tutan süreci zorla öldür; kilidin ömrü dolduğunda ürünün yeniden satılabilir olduğunu doğrula. Son olarak kilit bekleme sürelerini logla. Bekleme süreleri sürekli artıyorsa kilit kapsamın çok geniştir ya da teslimat içinde kilit altında yapılmaması gereken bir iş (mail gönderimi, fatura üretimi, dış API çağrısı) duruyordur. Bu işleri kilidin dışına taşımak, hem hızını hem güvenliğini birlikte artırır.
| Kontrol maddesi | Nasıl doğrulanır | Sorumlu katman | Öncelik |
|---|---|---|---|
| Kilit adı ürün bazlı | Log'da anahtar deseni incelenir | Teslimat servisi | Yüksek |
| Her kilitte süre sınırı var | Kilit çağrılarında TTL/timeout aranır | Altyapı | Kritik |
| Atomik stok seçimi | Etkilenen satır sayısı kontrol edilir | Veri katmanı | Kritik |
| Kuyruk işi tekrar güvenli | Aynı iş iki kez çalıştırılır | Kuyruk | Yüksek |
| Mail/fatura kilit dışında | Kilit süresi ölçülür | Teslimat servisi | Orta |
| Eşzamanlı yük testi | 20 istek, 1 teslimat | QA | Kritik |
| Kilit bekleme metriği | Panelde grafik/log takibi | İzleme | Orta |
Bunu sıfırdan mı yazmalı, hazır katman mı almalı?
Dağıtık kilit yazmak zor değil; doğru yazmak zor. Süre sınırı, yenileme, sahiplik doğrulaması, kilit serbest bırakılırken başkasının kilidini silmeme kontrolü, kuyruk tarafında tekrar güvenliği... Her biri küçük ama biri eksik kaldığında koruma yanılsamaya dönüşür. Pinova'nın teslimat çekirdeği bu kontrolleri hazır getirir: ürün bazlı kilit anahtarları, atomik stok seçimi, işlem sınırı içinde bakiye ve stok bütünlüğü, tekrar çalıştırılabilir teslimat işleri. Sen manuel teslimatla otomatik teslimatı aynı panelde yönetirken, altta hangi kilidin ne zaman alındığını düşünmek zorunda kalmazsın. Katmanların listesini özellikler bölümünde, lisans seçeneklerini fiyat tablosunda bulabilirsin.
Aynı kodu iki kez satmayı bugün bitir
Pinova, stok seçiminden bakiye hareketine kadar teslimat yolunun tamamını kilit ve işlem güvencesiyle çalıştırır. Kendi kilit altyapını yazmadan üretime geç.
Paylaşımlı hostingteyim, Redis kuramıyorum. Ne yapmalıyım?
MySQL tarafındaki adlandırılmış kilitler ve satır kilitleri senin için yeterli olur. Aynı veritabanına bağlanan tüm süreçler bu kilitlere saygı duyar, ek servis gerekmez. Redis'i ancak birden fazla uygulama sunucusuna geçtiğinde düşünmelisin.
Kilit siteyi yavaşlatır mı?
Dar kapsamlı bir kilit pratikte fark edilmez, çünkü yalnızca aynı ürünü aynı anda almak isteyen istekleri sıraya sokar. Yavaşlama, kilit içinde mail gönderimi veya dış API çağrısı gibi uzun işler yapıldığında ortaya çıkar; bu işleri kilidin dışına taşı.
Kilit tutan süreç çökerse ürün satılamaz mı kalır?
Süre sınırı koyduysan kalmaz. Kilit ömrü dolduğunda kendiliğinden serbest kalır ve ürün yeniden satılabilir hale gelir. Süre sınırsız kilit, çift teslimattan daha büyük bir problemdir.
Manuel teslimat yapan yöneticiyi de kilit kapsamına almalı mıyım?
Kesinlikle. Panel üzerinden elle yapılan teslimatlar, otomatik akışla aynı stok satırına dokunur. Aynı kilit ve aynı atomik seçim kuralları yönetici işlemleri için de geçerli olmalı.
Yarış koşulları sessiz çalışır: seni arayan müşteri değil, ay sonunda eksik çıkan stoktur. Bu yüzden kilit kurmayı ertelenebilir bir iyileştirme değil, satışın ön koşulu saymak gerekir. Tek stoklu bir ürüne aynı anda yirmi istek geldiğinde ne olduğunu kendi gözünle görmek istersen canlı demo panelinde bir test ürünü açıp deneyebilirsin; tek teslimat ve dürüst bir "stok tükendi" mesajı gördüğünde bu yazının neyi anlatmaya çalıştığı netleşir.

