Çoğu satıcı çift teslimatı bir kaza sanır. "Bir kez oldu, bir daha olmaz" diye geçiştirir, müşteriye jest yapar, kodu zarara yazar ve devam eder. Oysa çift teslimat kaza değildir; sistemin sessiz bir mantık boşluğunu doldurma biçimidir. Aynı boşluk bugün bir kez tetiklendiyse, yarın kampanya gününde saatte on kez tetiklenir. Çünkü tetikleyici müşterinin niyeti değil, trafiğin yoğunluğudur.
İşin can sıkıcı tarafı şu: çift teslimat yaşandığında kimse suçlu görünmez. Ödeme sağlayıcısı "bildirimi gönderdim" der, müşteri "ben sadece butona bastım" der, sen de panelde tek sipariş görürsün. Ama stoktan iki kod düşmüştür. Bu yazıda, bir e-pin satış scripti içinde çift teslimatın tam olarak hangi milisaniyede doğduğunu, hangi katmanın onu daha doğmadan boğduğunu ve satıcı olarak kendi kurulumunu nasıl denetleyeceğini anlatıyorum. Teknik terimleri kullanacağım ama hepsini kasadaki para diliyle karşılığını vererek.
Çoğu Satıcı Çift Teslimatı "Nadir Kaza" Sanır — Oysa Sistem Onu Üretiyor
Dijital ürün satışında teslimat, fiziksel kargodan farklı olarak geri alınamaz. Kargoyu iade alırsın, kodu alamazsın. Kod ekranı gördüğü an değerini kaybeder. Dolayısıyla bir dijital ürün satış scripti için "iki kez göndermemek", "hızlı göndermek"ten daha kritik bir görevdir. Ama piyasadaki pek çok kurulum tam tersini optimize eder: hız için önbellek, hız için asenkron istek, hız için ödeme dönüşünde anında teslimat. Kilit ve tekillik kontrolü ise "nasılsa aynı anda iki şey olmaz" varsayımıyla atlanır.
Aynı anda iki şey olur. Müşteri ödeme ekranında yavaş yüklenen sayfayı iki kez yeniler. Ödeme sağlayıcısı ilk bildirimine yanıt alamayınca aynı bildirimi 30 saniye sonra tekrar yollar. Mobil operatör bağlantıyı düşürüp isteği yeniden gönderir. Bunların üçü de senin sunucuna bakınca ayırt edilemez: geçerli ödeme, geçerli sipariş, geçerli teslimat talebi. Ayırt edecek tek şey, scriptin hafızasıdır.
Aynı Siparişin İki Kez İşlenmesi Tam Olarak Nerede Başlıyor?
Kritik pencere, ödemenin onaylandığı an ile siparişin "teslim edildi" olarak işaretlendiği an arasındaki boşluktur. Bu boşluk çoğu kurulumda 200 milisaniye ile 3 saniye arasında değişir; içinde stok sorgusu, kod seçimi, kodun rezerve edilmesi, e-posta gönderimi ve durum güncellemesi vardır. E-posta gönderimini bu zincirin içine koyduysan boşluk ikiye katlanır, çünkü posta sunucusu yanıt verene kadar sipariş hâlâ "bekliyor" durumundadır.
İki istek bu boşluğa aynı anda girdiğinde ikisi de aynı cevabı alır: "bu sipariş teslim edilmemiş." İkisi de kod çeker, ikisi de gönderir, ikincisi birincinin yazdığı durumu üzerine yazar. Panelde tek satır görürsün, stokta iki kod eksiktir. Buna yarış koşulu deniyor ve çözümü kodu hızlandırmak değil, pencereyi tek kişilik hale getirmektir.
| Senaryo | Gerçek tetikleyici | Tipik sonuç | Kapatan mekanizma |
|---|---|---|---|
| Müşteri ödeme dönüş sayfasını yeniliyor | Tarayıcı aynı isteği tekrar gönderiyor | 2 kod, 1 tahsilat | Sipariş bazlı tekillik anahtarı |
| Ödeme sağlayıcısı bildirimi tekrarlıyor | İlk bildirime 200 yanıtı dönülmemiş | 2-3 kod, 1 tahsilat | İşlem kimliği kaydı + hızlı yanıt |
| İki yönetici aynı siparişi elle onaylıyor | Panelde durum yenilenmemiş | 2 kod, müşteri memnun, kasa eksik | Satır kilidi + durum doğrulama |
| Otomatik teslimat ile elle teslimat çakışıyor | Kuyruk görevi geç tamamlanıyor | 2 kod, karışık kayıt | Tek teslimat yolu ilkesi |
| Bayi API'si zaman aşımı sonrası tekrar deniyor | Yanıt gelmedi diye yeniden istek | Tedarikçiden 2 kod satın alınıyor | İstek kimliğiyle tekrar denemesi güvenli çağrı |
Idempotency Anahtarı Neden Kodun Kendisinden Daha Değerli?
Idempotency, aynı işlemin kaç kez çalıştırıldığının sonucu değiştirmemesi demektir. Pratikte şöyle kurulur: teslimat isteğine sipariş numarası, kalem kimliği ve ödeme işlem kimliğinden türeyen tek bir anahtar üretilir ve bu anahtar veritabanında tekil indeks ile korunan bir tabloya yazılır. İkinci istek aynı anahtarı yazmaya çalıştığında veritabanı reddeder. Script bu reddi hata olarak değil, "bu iş zaten yapıldı" cevabı olarak okur ve ilk teslimatın sonucunu aynen döndürür.
Buradaki incelik, kontrolün uygulama katmanında değil veritabanı katmanında yapılmasıdır. "Önce sorgula, yoksa ekle" mantığı iki isteğin arasına sığar; tekil indeks sığmaz. Bu yüzden ciddi bir e-pin yazılımı değerlendirirken sorulacak soru "çift teslimat oluyor mu" değil, "tekilliği hangi katmanda garanti ediyorsun" olmalıdır. Cevap "kontrol ediyoruz" ise yetersizdir; "veritabanı kısıtı var" ise doğru yoldasın.
Çift teslimat vakalarının kaynak dağılımı
- Tekrarlanan ödeme bildirimi 45%
- Sayfa yenileme / çift tıklama 25%
- Elle onay ile otomatiğin çakışması 20%
- Tedarikçi API tekrar denemesi 10%
Veritabanı Kilidi Olmadan Stoktan Kod Çekmek Neden Kumar?
Stok havuzundan kod seçmek, listeden ilk boş satırı okumak değildir. Doğru kurgu, kodu seçerken o satırı kilitlemek ve aynı sorgu içinde "rezerve" durumuna geçirmektir. Böylece ikinci istek aynı satırı göremez; görse bile kilit açılana kadar bekler, açıldığında satır artık müsait değildir. Kodun müşteriye ulaştığı doğrulandıktan sonra rezerve durumu "teslim edildi"ye çevrilir.
Bu üç aşamalı durum modeli (müsait → rezerve → teslim) çift teslimatı önlemenin yanında başka bir sorunu da çözer: yarım kalmış teslimatlar. Posta sunucusu düşerse kod rezerve kalır, müşteriye gitmemiştir, zamanlı bir görev onu tekrar müsaite çevirir ya da yeniden gönderim için işaretler. Durum modeli olmayan bir epin yazılım kurulumunda ise aynı senaryo "kod gitti mi gitmedi mi" belirsizliğiyle sonuçlanır ve satıcı emin olamadığı için ikinci kodu elle gönderir. Zararın kaynağı teknik değil, bilgi eksikliğidir.
Ödeme Bildirimi İki Kez Gelirse Scriptin Ne Yapıyor?
Ödeme sağlayıcıları bildirim gönderdiğinde kısa süre içinde başarılı bir yanıt bekler. Yanıt gecikirse bildirimi tekrarlar; bu bir arıza değil, tasarım gereğidir. Dolayısıyla senin uç noktanın görevi işi bitirip yanıt vermek değil, işi kayda geçirip hemen yanıt vermek ve teslimatı arka plandaki tek bir işleyiciye bırakmaktır. Bildirim uç noktası ağırlaştıkça tekrar sayısı artar, tekrar sayısı arttıkça çift teslimat riski büyür.
Aynı uç noktada mutlaka işlem kimliği kaydı tutulmalı. Sağlayıcının gönderdiği işlem kimliği daha önce görülmüşse bildirim sessizce kabul edilip hiçbir şey yapılmamalı. Buna "tekrarı yut" davranışı diyorum ve bir e-pin satış yazılımı için tek satırlık koddan çok daha fazlasını ifade eder: sistemin dışarıdan gelen belirsizliği içeri sızdırmadığı anlamına gelir.
Teslimat e-postasını ödeme bildirimi zincirinin içinden çıkar. Bildirime 200 yanıtını 100 milisaniyede dön, postayı kuyruğa at. Tek başına bu değişiklik tekrarlanan bildirim kaynaklı çift teslimatların büyük kısmını keser.
Zarar Sonradan Nasıl Fark Edilir: Teslimat Günlüğü ve Günsonu Mutabakat
Önleme katmanı kurulsa bile denetim olmadan güven eksik kalır. İhtiyacın olan şey, her teslimat girişiminin ayrı satır olarak yazıldığı değiştirilemez bir günlüktür: hangi anahtar, hangi kod, hangi kanal, hangi zaman, sonuç ne. Bu günlük sayesinde "iki kez gitti mi" sorusu tartışma konusu olmaz, sorgu konusu olur.
Üstüne günsonu basit bir mutabakat koy: gün içinde teslim edilen kod sayısı ile satılan kalem sayısı eşit mi? Eşit değilse fark nereden geliyor? Bu kontrolü otomatikleştirdiğinde sızıntıyı müşteri şikayetinden değil, kendi raporundan öğrenirsin. Sağlam bir dijital ürün satış yazılımı ile amatör bir kurulum arasındaki fark tam olarak burada görünür; ikisi de satış yapar, biri ne olduğunu bilir.
| Kontrol | Neden gerekli | Nasıl doğrularsın |
|---|---|---|
| Teslimat kayıtlarında tekil indeks var mı | Uygulama kontrolü yarış koşuluna açıktır | Aynı siparişi iki sekmede onayla, ikincisi reddedilmeli |
| Kod seçimi kilitli sorguyla mı yapılıyor | Aynı kod iki isteğe düşmesin | Eşzamanlı iki ödeme bildirimi gönder, stok 1 düşmeli |
| Ödeme işlem kimliği saklanıyor mu | Tekrarlanan bildirim yutulmalı | Sağlayıcı panelinden bildirimi elle tekrar gönder |
| Kod durumları üç aşamalı mı | Yarım teslimat belirsizliği kalksın | Posta gönderimini bilerek başarısız yap |
| Bildirim uç noktası hızlı yanıt veriyor mu | Yavaş yanıt tekrar üretir | Yanıt süresini ölç, 300 ms altında olmalı |
| Teslimat günlüğü değiştirilemez mi | İtiraz anında delil gerekir | Kayıt silme/düzenleme yetkisini denetle |
| Günsonu mutabakat raporu var mı | Sızıntı kendiliğinden görünmez | Satılan kalem ile teslim kodu sayısını karşılaştır |
Teslimat güvenliğini şansa bırakma
Pinova, tekillik anahtarı, kilitli stok seçimi ve değiştirilemez teslimat günlüğünü kutudan çıktığı gibi getiren lisanslı bir e-pin satış yönetim yazılımıdır. Özellik listesini inceleyip kendi kurulumunla karşılaştırabilirsin.
Çift teslimat olduğunda kodu iptal edebilir miyim?
Tedarikçiye bağlı. Bazı sağlayıcılar kullanılmamış kodu iptal eder, çoğu etmez. Bu yüzden çözüm iptal değil, önlemedir; kod ekrana düştüğü an riski üstlenmiş olursun.
Sadece "butona iki kez basmayı engelle" demek yetmez mi?
Yetmez. Arayüzdeki engel vakaların yalnızca bir bölümünü kapsar; tekrarlanan ödeme bildirimleri ve elle onay çakışmaları tarayıcıdan bağımsız gerçekleşir. Koruma sunucu tarafında olmalı.
Küçük hacimde bu kadar mekanizma gereksiz değil mi?
Günde 20 sipariş alırken riski hiç görmezsin; kampanya günü 400 siparişte aynı boşluk defalarca tetiklenir. Mekanizmayı hacim büyümeden kurmak, büyüdükten sonra kurmaktan hem kolay hem ucuzdur.
Kendi scriptime bu katmanı sonradan ekleyebilir miyim?
Ekleyebilirsin ama teslimat akışının tek bir yerden geçmesi şartıyla. Üç farklı dosyadan kod gönderen bir yapıda tekillik garantisi kurmak, akışı baştan tek yola indirmekten daha zahmetlidir.
Kendi kurulumunu denetlemenin en hızlı yolu, yukarıdaki kontrol listesini tek tek uygulayıp hangi satırda "emin değilim" dediğini not almaktır. Emin olmadığın her satır, ileride kasadan çıkacak bir koddur. Karşılaştırma yapmak istersen canlı demo üzerinden teslimat akışını uçtan uca izleyebilir, fiyatlandırmaya göz atıp kendi hacmine uygun paketi seçebilirsin.

