Çoğu Laravel idempotency katmanı, altyapı problemine çözüm bulurken, iş sorununu atlamaktadır.
Bu katman, tekrarlanan HTTP isteklerini durdurur. Güzeldir. Ancak genellikle 10 dakika, 1 saat veya 24 saat gibi genel bir tekrar süresi ile bunu yaparlar; çünkü bu middleware tarafından kolayca desteklenir. Burada tasarım yanlışı yavaşça başlar.
Bir idempotency anahtarı sadece bir taşıma sorunu değildir. Bu, kullanıcı niyeti hakkında geçici bir iddiadır. Yani, bu istek aynı eylem olarak değerlendirilmelidir, eğer bu zaman dilimi içinde tekrar görünürse. Eğer bu zaman dilimi, temel iş niyetinden daha uzun sürerse, koruma katmanınız koruyucu olmaktan çıkar ve çarpıtıcı hale gelir.
Bu, Laravel idempotency TTL tasarımının gerçek dersidir: tekrar süresi, korunan iş niyeti sona erdiğinde sona ermeli, middleware’in varsayılan önbellek süresi sona erdiğinde değil.
Bu, ekiplerin düşündüğünden daha önemlidir. Kötü bir TTL, çift ücretlemeleri önleyebilir ama yine de kötü sonuçlar yaratabilir. Mevcut durumlardan sonra meşru bir yeniden denemeyi engelleyebilir, bir yanıtı iş akışının gerektirdiğinden uzun süre dondurabilir veya destek ekiplerinin “neden bu hala aynı istek olarak kabul ediliyor?” gibi olayları hata ayıklamak zorunda kalmasına neden olabilir. Bunlar teknik olarak doğru ama ürün açısından yanlış durumlar.
Yaygın Laravel Uygulaması Teknik Olarak İyidir Ama Kavramsal Olarak Zayıftır
Tipik kurulum şu şekilde görünür:
- istemci bir
Idempotency-Keybaşlığı gönderir - sunucu istek yükünü veya rota bağlamını hashler
- middleware yanıtı Redis, önbellek veya veritabanında saklar
- aynı anahtarla tekrarlanan istekler belirli bir yapılandırılmış TTL için aynı yanıtı tekrar alır
Bu makul bir altyapı başlangıç noktasıdır. Tekrar göndermeleri, mobil yeniden denemeleri, proxy tuhaflıklarını ve sabırsız çifte tıklamaları yönetir.
Problem, TTL’nin genellikle yanlış katmanda tanımlanmış olmasıdır.
Böyle bir rota düzeyinde varsayılan oluşturmak kolaydır:
final class IdempotencyMiddleware
{
public function handle($request, Closure $next)
{
$key = $request->header('Idempotency-Key');
$ttl = now()->addHour();
// lookup + replay logic
}
}
Ancak “bir saat” bir iş kuralı değildir. Bu bir kolaylık sabitidir.
Bu ayırt edici durum önemlidir çünkü aynı HTTP deseni, çok farklı iş eylemlerini temsil edebilir:
- ödeme oluşturma
- davetiye yeniden gönderme
- deneme süresini başlatma
- taslak teklif oluşturma
- iade yapma
- şifre sıfırlama e-postası gönderme
Bunların hepsi POST istekleri olabilir. Hiçbiri illa ki “aynı eylem” tanımına sahip değildir.
Ekiplerin Yaptığı Yanlışlık
Ekipler genellikle idempotency katmanının sadece şu soruya cevap vermesi gerektiğini varsayar:
Bu istek bir tekrar mı?
Daha iyi soru ise:
Bu istek hala aynı iş girişimi olarak ne kadar süreyle değerlendirilmeli?
İkinci soru, TTL’nin ne zaman geldiğini belirler.
TTL, Niyet Süresinden Türemelidir, Sadece Ağ Belirsizliğinden Değil
İdempotency, sistemlerin belirsiz olduğunu kabul eder.
İstemci, ilk isteğin başarılı olup olmadığını bilemeyebilir. Tarayıcı yeniden deneyebilir. Mobil ağ, gönderimden sonra düşebilir. Bir işçi, yan tesirin gerçekleştiği sırada zaman aşımına uğrayabilir.
Böylece, idempotency’nin bir kısmı taşıma belirsizliği ile ilgilidir.
Ancak tekrar penceresi sadece altyapı kaygısıyla belirlenmemelidir. Bir insanın veya üst sistemin hala geçerli bir aynı girişim anlamına gelebileceği süreye dayalı olarak belirlenmelidir.
Bu, tasarım için anahtar bir kaymadır.
Ayrı Tutulması Gereken Üç Niyet Türü
Pratikte, tekrar eden istekler genellikle bu üç kategoriden birine girer:
- Yeniden Deneme Niyeti — “Önceki girişimimin başarılı olup olmadığından emin değilim, aynı şeyi tekrar deniyorum.”
- Tekrar Niyeti — “Şimdi gerçekten tekrar eylemi gerçekleştirmek istiyorum.”
- Değiştirme Niyeti — “Aynı hedefi istiyorum, ancak değişen girdiler veya değişen koşullarla.”
İyi bir idempotency TTL, yeniden deneme niyetini korur ancak tekrar veya değiştirme niyetini gereksiz yere uzun süre baskı altında tutmaz.
Eğer TTL’niz çok kısa ise, tekrar korumasını kaybedersiniz.
Eğer TTL’niz çok uzun ise, geçmişteki bir girişimi, kullanıcının gerçek anlamını aşan bir politika haline getirirsiniz.
Tekrar Penceresi Bir İş Beyanıdır
Bir ödeme isteği üzerindeki 24 saatlik TTL, şunu söyler:
Önümüzdeki 24 saat içinde, sistem tekrar bu anahtarla gönderilen bir iletimi aynı ödeme girişimi olarak değerlendirmeye devam edecektir.
Bu bazı iş akışlarında doğru olabilir. Diğerlerinde ise tamamen yanlıştır.
Bu nedenle genel middleware varsayıfları çok tehlikelidir. İş kararını altyapının derinliklerine saklar.
İlk Olarak İş Akışını Modellemeye Başlayın, Rotayı Değil
Daha iyi Laravel idempotency TTL kararları almak istiyorsanız, rota katılımcısı olan iş akışından başlayın.
Dört soru sorun:
- Korumak istediğiniz kesin eylem nedir?
- Yeniden deneme belirsizliği ne kadar süreyle gerçekçi olarak devam eder?
- Tekrar eden bir istek ne zaman meşru bir yeni girişim haline gelir?
- Hangi iş bağlamındaki değişiklik, aynılık geçerliliğini geçersiz kılmalıdır?
Bu sorular, “hangi varsayılan TTL güvenli hissediliyor?” sorusundan çok daha yararlıdır.
Örnek 1: Fatura Ödemesi
Varsayalım ki bir kullanıcı bir faturayı mobil uygulama üzerinden ödüyor. İlk istek sunucu tarafında başarılı olsa da, istemci yanıtı almadan bağlantısını kaybediyor.
Bu durumda, birkaç dakikalık yeniden deneme süresi korumak mantıklıdır. Kullanıcı ödeme başarılı olup olmadığını bilmediğinden tekrar tıklayabilir.
Ancak eğer TTL’niz 24 saat sürüyorsa, aşağıdakilerden sonra meşru bir ikinci ödeme girişimini engelleyip:
- ödeme yöntemini değiştirmiş
- banka kimlik doğrulama sorunlarından sonra yeniden denemiş
- başka bir cihazdan daha sonra devam etmiş
Orijinal tekrar riski gerçekti. Ancak 24 saatlik aynılık varsayımı doğru değildi.
İş bilincine sahip bir tasarım, ilk girişim için 5 veya 10 dakikalık bir tekrar penceresi seçerken, geçersiz tekrar yerleşimi önlemede fatura durumunu gibi daha derin alan kısıtlamalarına dayanabilir.
Örnek 2: Ekip Davetiyesi E-postası
Bir kullanıcı “davet gönder” düğmesine iki kez tıklıyor çünkü buton gecikti. Bu klasik tekrarlanan gönderim alanıdır.
Burada 10 veya 15 dakikalık bir TTL yeterli olabilir. Spam benzeri yanlışlıkları önlemek istersiniz, ancak sistemin daha sonra orijinal davetiye süresi dolmuşsa veya alıcı hiç görmediyse, geçerli bir yeniden gönderimi aynı olay olarak kabul etmesini istemezsiniz.
Örnek 3: Teklif Taslağı Oluşturma
Bir satış temsilcisi bir taslak teklif oluşturuyor, dizüstü bilgisayarını kapatıyor ve sonra geri geliyor. Genel bir 1 saatlik TTL, yeniden gönderimin eski taslak oluşturulmasını ortaya çıkarabilir, oysa temsilci şimdi yeni bir teklif versiyonu bekliyordur.
Bu, idempotency TTL’nin anlamın yanlış katmanını koruduğu bir işarettir.
Bu tür bir iş akışında, gerçek tekrar koruması çok daha kısa olması gerekebilir veya anahtar, sadece rota ve yüklenmekle kalmayıp, istemci tarafındaki taslak oturumuna bağlı olmalıdır.
Anahtar Tasarımı ve TTL Tasarımı Birlikte Çalışmalıdır
Ekipler genellikle TTL’ye takıntı yaparken anahtar kapsamını ihmal ediyor. Bu bir hatadır.
Tekrar penceresi, anahtarın neyi “aynı eylem” olarak kabul ettiğine göre anlam kazanır.
Geniş bir anahtar ile uzun bir TTL, ürün hatalarının altyapı başarısı olarak görünmesinin en kolay yoludur.
Kötü Anahtar Şekli
user:42:create-payment
Bu anahtar, aynı kullanıcı tarafından TTL içinde yapılan her ödeme girişiminin aynı eylem olabileceğini belirtmektedir. Bu çok geniştir.
Daha İyi Anahtar Şekli
invoice:inv_991:payment_attempt:client_key_abc123
Bu anahtar, aynılık olgusunun belirli bir fatura ödeme girişimi bağlamına ait olduğunu belirtmektedir. Bu çok daha güvenlidir.
Hatırlanacak Kural
- Anahtar kapsamı, aynı eylem olarak neyin sayılacağını tanımlar.
- TTL, o aynılığın ne kadar süreyle inandırıcı kaldığını tanımlar.
Her iki durum da yanlışsa, idempotency katmanı bile hala kötü davranabilir.
Pratik Bir Laravel Deseni
Uygulamanın, middleware’in rotadan çok fazla şey çıkarması yerine, normalleştirilmiş bir idempotency bağlamını tanımlamasına izin verin.
interface DefinesIdempotencyContext
{
public function idempotencyKeyScope(): string;
public function idempotencyTtlSeconds(): int;
}
Böylece spesifik istekler veya eylemler bunu uygulayabilir:
final class PayInvoiceRequest extends FormRequest implements DefinesIdempotencyContext
{
public function idempotencyKeyScope(): string
{
return 'invoice:' . $this->route()->id . ;
}
public function idempotencyTtlSeconds(): int
{
return 600;
}
}
Şimdi middleware, taşıma boru hattı haline gelir ve işin aynılığının sahibi olmaz.
İşin Değiştiği Zaman Aynılık ile İlgili Karar Vermek için Alan Katmanını Kullanın
TTL tasarımını geliştirmenin en iyi yollarından biri, statik rota yapılandırmaları üzerinden düşünmeyi bırakmak ve alan durum geçişleri üzerinden düşünmektir.
Çünkü birçok gerçek iş akışında, aynılık sadece zamanla sona ermez. İş durumu değiştiğinde sona erer.
Ödeme Akışları İyi Bir Örnektir
Bir ödeme girişimi, sadece 10 dakika sonra değil, aynı zamanda şu durumlarda “aynı girişim” olmaktan çıkabilir:
- fatura durumu değişirse
- ödeme yöntemi değişirse
- kimlik doğrulama zorluğu yeniden başlatılırsa
- müşteri açıkça yeni bir kefalet veya yolu seçerse
Bu, zamanın tek başına bazen yanlış bir kontrol düzlemi olduğunu gösterir.
Hibrit Bir Yaklaşım Daha İyi Çalışır
TTL’yi taşıma düzeyindeki tekrar penceresi olarak kullanın, ancak alan durumu, tekrarın hala geçerli olup olmadığını sınırlasın.
Örneğin:
final class PaymentIdempotencyPolicy
{
public function replayAllowed(Invoice $invoice, array $requestData): bool
{
if ($invoice->status === ) {
return true;
}
if ($invoice->payment_method_id !== $requestData[]) {
return false;
}
return true;
}
}
Burada önemli olan, bu tam kodun eksiksiz olduğu değil, alan durumunun, eski girişimin yeni biriyle hala anlamlı bir şekilde örtüşüp örtüşmediğine karar vermekte rol oynamasıdır.
Bu, iki olumsuz uç durumu önlemenizi sağlar:
- TTL çok kısa olur ve yeniden denemeler korumasız kalır.
- TTL çok uzun olur, değişen kullanıcı niyeti eski bir aynılık tarafından engellenir.
Laravel Middleware TTL Politikasını Delegeli Hale Getirir, Sahibi Olmaz
Birçok idempotency uygulaması, middleware’in çok fazla mantığı sahiplenmesi nedeniyle katı hale gelir.
Middleware, şu aşamalarda iyi bir yerdir:
- Anahtarı okumak
- Saklı girişimleri incelemek
- Yanıtları tekrar oynatmak için kısa devre yapmak
- Başarılı sonuçları kalıcı hale getirmek
Middleware, iş akışı anlamlarını kodlamak için kötü bir yerdir.
Daha İyi Bir Mimari
Middleware’in bir politikanın tekrar kurallarını sormasını sağlayın.
interface IdempotencyPolicy
{
public function scope(Request $request): string;
public function ttlSeconds(Request $request): int;
}
Daha sonra bu politikaları faaliyet veya rotaya göre bağlayın:
final class SendInviteIdempotencyPolicy implements IdempotencyPolicy
{
public function scope(Request $request): string
return . $request->route()->id . ;
}
public function ttlSeconds(Request $request): int
return ;
}
}
Ya da, iş kurallarını uygulama servislerine yakın tutmayı tercih ederseniz, hizmetin TTL’yi açığa çıkarmasına izin verin:
final class SendWorkspaceInvite
public function idempotencyTtlSeconds(): int
return ;
}
}
Büyük kazanım, stil değil, tekrar penceresinin artık iş akışını anlamaya sahip bir şeye ait olmasıdır.
Tekrar Oynatılan Yanıtların Değişen Niyeti Gizlemesine İzin Vermeyin
Bir subtal hata durumu, teknik olarak doğru ama anlamı eski olan bir yanıtın tekrar oynatılmasıdır.
Örneğin, orijinal istek şu yanıtı döndürüyor:
{
"status": ,
"payment_id":
}
Aynı anahtarla sonraki bir yeniden denemede, bu yanıt tekrar oynatılır, oysa fatura durumu failed veya ödeme girişimi terk edilmiştir.
Middleware’in bakış açısından, tekrar başarılı olmuştur.
Ürün perspektifinde, yanıt artık yanıltıcı olabilir.
Bu, TTL’nin tembel olamayacağı Nedendir
Eğer tekrar penceresi çok uzunsa, sadece tekrarları önlemekle kalmaz, aynı zamanda eski bir yorumun da yaşam süresini uzatırsınız.
Bu, yanıtların hala geçerli olduğunu varsayan istemciler, arka plan işçileri ve destek personeli için kafa karıştırabilir.
Daha kısa, iş akışına duyarlı bir TTL bu riski azaltır. Ayrıca, uygun olduğunda tekrar katmanından alan bilgisi gerektiren durumları döndürmek de bu riski azaltır.
Laravel Ekipleri İçin Pratik Bir TTL Seçim Çerçevesi
Operasyonel bir şey istiyorsanız, bu çerçeveyi kullanın.
1. Adım: Tekrar Riskini Belirleyin
Gerçekten ne zararı önlüyorsunuz?
- çift ücret?
- çift e-posta?
- tekrar eden taslak?
- üçüncü taraf API üzerinde yinelenen yan etki?
Daha yüksek riskli yan etkiler, daha güçlü idempotency gerektirir, ancak otomatik olarak daha uzun aynılık pencereleri anlamına gelmez.
2. Adım: Gerçek Yeniden Deneme Davranışını Ölçün
Meşru yeniden denemeler, ilk girişimden ne kadar süre sonra gerçekleşiyor?
Yüzde 95 kullanıcı yeniden denemesi 2 dakika içinde oluyorsa, 1 saatlik bir TTL muhtemelen bir politika kaymasıdır, koruma değil.
3. Adım: İkinci Girişimin Meşru Hale Geldiği Sınırı Tanımlayın
Sistem ne zaman “aynı girişim” varsayımını sona erdirmelidir?
Bu, aşağıdaki üzerine olabilir:
- geçen zaman
- ödeme yöntemi değişikliği
- iş akışı durumu değişikliği
- kullanıcı eylemi yeniden başlatma
4. Adım: Korumak İstediğiniz Eylemi Kapsayan En Dar Anahtarı Seçin
Gerçek aynılık, fatura kimliği, taslak kimliği, davet hedefi veya ödeme oturumu üzerine değilse, kullanıcı kimliğine göre anahtarlamayın.
5. Adım: TTL Seçimini Uygulama Politikasında, Sihirli Middleware Sabitlerinde Değil Yerleştirin
Bu, sürdürülebilirlik adımıdır. Eğer geliştiriciler bir rotanın neden TTL’si olduğunu göremiyorlarsa, tasarım, kargo kültürü varsayımları haline gelecektir.
Üretimde Kaçınacağım Şeyler
Hemen güvenilir bulduğum birkaç örüntü var.
“Tüm POST rotaları için tek bir TTL”
Bu uygulamak kolaydır ve neredeyse her zaman kavramsal olarak yanlıştır.
“Ödemeler korkutucu olduğu için 24 saat”
Korku bir politika değildir. Gerçek soru, aynı ödeme niyetinin bu kadar uzun süre var olup olmadığıdır.
“Manuel temizliğe kadar her zaman tekrar oynat”
Bu artık idempotency değildir. Bu, kazara arşivleme davranışıdır.
“Önbellek kolaylığı tarafından seçilen TTL”
Eğer süre, Redis alışkanlığına veya middleware paket varsayılanına uymak için varsa, bu bir kırmızı bayraktır.
Gerçekten Geçerli Olan Kural
İstediğiniz şey, Laravel idempotency TTL için bir keskin kuralsa, bu olsun:
Tekrar penceresi, yeniden gönderinin hala dürüstçe aynı iş girişimini temsil ettiği kadar sürmelidir.
Daha uzun değil.
Bu, idempotency TTL’nin sadece bir altyapı düğmesi olmadığı anlamına gelir. Bu, iş akışı tasarımınızın bir parçasıdır.
Laravel terimleriyle, taşıma katmanı idempotency’yi uygulayabilir ancak uygulama katmanı, ne zaman aynılığın sona ereceğini tanımlamalıdır. Bu genellikle TTL kararlarını genel middleware varsayımlarından çıkararak, istek politikalarına, eylem sınıflarına veya alan bilgisine duyarlı idempotency kurallarına yerleştirmek anlamına gelir.
Çünkü tekrar koruma gerçek hedef değildir. Gerçek hedef, iş niyetini kazara ötesine genişletmeden korumaktır.
TTL niyetin ötesine geçtiğinde, sistem dikkatli olmayı bırakır ve ısrarcı hale gelir. Ve üretimde, ısrarcı altyapı, güvenle daha fazla iş hatası yaratmanın bir yoludur.
Kaynak: Orijinal Makale
- Yaygın Laravel Uygulaması Teknik Olarak İyidir Ama Kavramsal Olarak Zayıftır
- TTL, Niyet Süresinden Türemelidir, Sadece Ağ Belirsizliğinden Değil
- İlk Olarak İş Akışını Modellemeye Başlayın, Rotayı Değil
- Anahtar Tasarımı ve TTL Tasarımı Birlikte Çalışmalıdır
- İşin Değiştiği Zaman Aynılık ile İlgili Karar Vermek için Alan Katmanını Kullanın
- Laravel Middleware TTL Politikasını Delegeli Hale Getirir, Sahibi Olmaz
- Tekrar Oynatılan Yanıtların Değişen Niyeti Gizlemesine İzin Vermeyin
- Laravel Ekipleri İçin Pratik Bir TTL Seçim Çerçevesi
- 1. Adım: Tekrar Riskini Belirleyin
- 2. Adım: Gerçek Yeniden Deneme Davranışını Ölçün
- 3. Adım: İkinci Girişimin Meşru Hale Geldiği Sınırı Tanımlayın
- 4. Adım: Korumak İstediğiniz Eylemi Kapsayan En Dar Anahtarı Seçin
- 5. Adım: TTL Seçimini Uygulama Politikasında, Sihirli Middleware Sabitlerinde Değil Yerleştirin
- Üretimde Kaçınacağım Şeyler
- “Tüm POST rotaları için tek bir TTL”
- “Ödemeler korkutucu olduğu için 24 saat”
- “Manuel temizliğe kadar her zaman tekrar oynat”
- “Önbellek kolaylığı tarafından seçilen TTL”
- Gerçekten Geçerli Olan Kural


