Yavaş bağlantılar için Kotlin ağ işlemleri: zaman aşımı ve güvenli yeniden denemeler
Pratik Kotlin ağ ipuçları: yavaş bağlantılarda zaman aşımı ayarlayın, güvenli önbellekleme yapın, kopyaları önleyecek yeniden denemeler uygulayın ve kararsız mobil ağlarda kritik işlemleri koruyun.

Yavaş ve kararsız bağlantılarda neler bozulur
Mobilde “yavaş”, genellikle “internet yok” anlamına gelmez. Çoğunlukla bağlantı çalışıyor ancak kısa kesintiler halinde. Bir istek 8–20 saniye sürebilir, yarıda takılabilir, sonra tamamlanabilir. Veya bir an başarılı olup, telefon Wi‑Fi'dan LTE'ye geçtiği, zayıf alana girildiği veya işletim sistemi uygulamayı arka plana attığı için bir sonraki anda başarısız olabilir.
“Kararsız” daha kötüdür. Paketler düşer, DNS sorguları zaman aşımına uğrar, TLS el sıkışmaları başarısız olur ve bağlantılar rastgele sıfırlanır. Kodda her şeyi “doğru” yapsanız bile alan koşulları yüzünden hatalar görmeniz mümkündür çünkü ağ sizin altınızda değişiyor.
İşte varsayılan ayarların bozulduğu yer burasıdır. Birçok uygulama zaman aşımı, yeniden deneme ve önbellekleme için kütüphane varsayılanlarına güvenir, ama gerçek insanlar için “yeterince iyi”nin ne olduğunu belirlemez. Varsayılanlar genellikle stabil Wi‑Fi ve hızlı API'ler için ayarlanmıştır, bir banliyö treni, asansör yolculuğu veya kalabalık bir kafe için değil.
Kullanıcılar “socket zaman aşımı” ya da “HTTP 503” demezler. Semptomları fark ederler: sonsuz dönen göstergeler, uzun beklemeden sonra aniden hatalar (sonra tekrar deneyince çalışır), çift işlemler (iki rezervasyon, iki sipariş, çift ücretlendirme), kaybolan güncellemeler ve arayüzün “başarısız” dediği ama sunucunun aslında başardığı karışık durumlar.
Yavaş ağlar küçük tasarım boşluklarını para ve güven sorunlarına dönüştürür. Uygulama “hala gönderiliyor”, “başarısız” ve “tamamlandı”yı net ayırt etmezse kullanıcı tekrar dokunur. İstemci körü körüne yeniden deniyorsa kopyalar oluşabilir. Sunucu idempotency desteklemiyorsa tek bir sallantılı bağlantı birden fazla “başarılı” yazma üretebilir.
“Kritik işlemler”, en fazla bir kez gerçekleşmesi gereken ve doğru olması gereken her şeydir: ödemeler, ödeme gönderimleri, bir slot rezervasyonu, puan transferi, şifre değişikliği, bir teslimat adresinin kaydedilmesi, hak talebi gönderme veya onay gönderme gibi.
Gerçekçi bir örnek: biri zayıf LTE üzerinde ödeme gönderiyor. Uygulama isteği gönderiyor, sonra cevap gelmeden bağlantı düşüyor. Kullanıcı bir hata görüyor, tekrar “Öde”ye dokunuyor ve şimdi iki istek sunucuya ulaşıyor. Net kurallar yoksa uygulama yeniden denemeli mi, beklemeli mi yoksa durmalı mı karar veremez. Kullanıcı da tekrar denemesi gerekip gerekmediğini anlayamaz.
Kodu ayarlamadan önce kurallarınızı belirleyin
Bağlantılar yavaş veya kararsız olduğunda, hataların çoğu HTTP istemcisinden değil belirsiz kurallardan kaynaklanır. Zaman aşımı, önbellekleme veya yeniden deneme ayarlarına dokunmadan önce “doğru”nun uygulamanız için ne anlama geldiğini yazın.
Tekrar çalışmaması gereken işlemlerle başlayın. Bunlar genellikle para ve hesap işlemleridir: sipariş verme, kartı ücretlendirme, ödeme gönderimi, şifre değiştirme, hesabı silme. Kullanıcı iki kez dokunsa ya da uygulama yeniden denese bile sunucu bunu tek bir istek olarak ele almalıdır. Eğer bunu henüz garanti edemiyorsanız, bu endpointleri “otomatik yeniden deneme yok” olarak değerlendirin.
Sonra, ağ kötü olduğunda her ekranın ne yapmasına izin verildiğine karar verin. Bazı ekranlar çevrimdışı bile faydalı olabilir (bilinen son profil, önceki siparişler). Diğerleri sadece okunur olmalı veya net bir “tekrar deneyin” durumu göstermeli (stok sayıları, canlı fiyatlar). Bu beklentileri karıştırmak kafa karıştırıcı UI ve riskli önbellekleme ile sonuçlanır.
Her işlem için kabul edilebilir bekleme süresini, geliştiricinin hoşuna giden bir sayı yerine kullanıcıların nasıl düşündüğüne göre belirleyin. Giriş kısa bir beklemeyi tolere edebilir. Dosya yükleme daha uzun süre gerektirir. Checkout hızlı hissettirmeli ama aynı zamanda güvenli olmalıdır. 30 saniyelik bir zaman aşımı kağıt üzerinde “güvenilir” olabilir ama kullanıcı için hâlâ bozuk hissettirebilir.
Son olarak, cihazda ne saklayacağınıza ve ne kadar süreyle saklayacağınıza karar verin. Önbelleğe alınan veriler yardımcı olur ama bayat veri yanlış seçimlere neden olabilir (eski fiyatlar, süresi dolmuş uygunluk).
Kuralları herkesin bulabileceği bir yere yazın (bir README yeterlidir). Basit tutun:
- Hangi endpointler “kopyalanmamalı” ve idempotency gerektiriyor?
- Hangi ekranlar çevrimdışı çalışmalı, hangileri çevrimdışıyken sadece okunur olmalı?
- İşlem başına maksimum bekleme süresi nedir (giriş, feed yenileme, yükleme, checkout)?
- Cihazda ne önbelleğe alınabilir ve ne kadar süreyle?
- Başarısızlık sonrası hata mı gösterilir, ileriye sıraya mı alınır yoksa manuel yeniden deneme mi istenir?
Kurallar netleşince zaman aşımı değerleri, önbellek başlıkları, yeniden deneme politikası ve UI durumlarını uygulamak ve test etmek çok daha kolay olur.
Gerçekçi kullanıcı beklilerine uyan zaman aşımı ayarları
Yavaş ağlar farklı şekillerde başarısız olur. İyi bir zaman aşımı ayarı sadece “bir sayı seçmek” değildir. Kullanıcının ne yapmaya çalıştığı ile eşleşir ve uygulamanın kurtarması için yeterince hızlı başarısız olur.
Üç zaman aşımı, sade şekilde:
connect timeout: sunucuya bağlantı kurulurken (DNS, TCP, TLS) ne kadar bekleyeceğiniz. Bu başarısızsa istek hiç başlamamıştır.write timeout: istek gövdesini gönderirken ne kadar bekleyeceğiniz (yüklemeler, büyük JSON, yavaş uplink).read timeout: istek gönderildikten sonra sunucudan veri gelmesini ne kadar bekleyeceğiniz. Bu çoğunlukla zayıf mobil ağlarda görülür.
Zaman aşımı değerleri ekran ve risk düzeyi ile uyumlu olmalı. Bir feed daha yavaş olabilir. Kritik bir işlem ya tamamlanmalı ya da açıkça başarısız olmalı ki kullanıcı bir sonraki adımı seçebilsin.
Pratik bir başlangıç (ölçüm sonrası ayarlayın):
- Liste yükleme (düşük risk): connect 5–10s, read 20–30s, write 10–15s.
- Yazarken arama (search-as-you-type): connect 3–5s, read 5–10s, write 5–10s.
- Kritik işlemler (yüksek risk, ör. "Öde" veya "Siparişi gönder"): connect 5–10s, read 30–60s, write 15–30s.
Tutarlılık mükemmelliktan daha önemlidir. Kullanıcı “Gönder”e dokunup iki dakika spinner görürse tekrar dokunacaktır.
UI tarafında da bir üst sınır ekleyerek “sonsuz yüklemeyi” önleyin. Hemen ilerlemeyi gösterin, iptal etme olanağı sunun ve (örneğin) 20–30 saniye sonra “Hâlâ deniyoruz…” gösterip yeniden deneme veya bağlantıyı kontrol etme seçenekleri sunun. Bu, ağ kütüphanesi hâlâ bekliyor olsa bile deneyimi dürüst tutar.
Bir zaman aşımı olduğunda, desenleri sonradan inceleyebilmek için kimlik bilgisi içermeyen yeterli log kaydı tutun. Yararlı alanlar: URL yolu (tam sorgu değil), HTTP metodu, durum (varsa), zaman kırılımı (connect vs write vs read), ağ türü (Wi‑Fi, hücresel, uçak modu), tahmini istek/cevap boyutu ve bir istek kimliği ki istemci logları ile sunucu loglarını eşleştirebilesiniz.
Basit ve tutarlı bir Kotlin ağ yapılandırması
Bağlantılar yavaşsa istemci kurulumundaki küçük tutarsızlıklar büyük sorunlara dönüşür. Temiz bir temel sorunları daha hızlı hata ayıklamaya yardımcı olur ve her isteğe aynı kuralları verir.
Tek bir client, tek bir politika
HTTP client'inizi (çoğunlukla Retrofit tarafından kullanılan bir OkHttpClient) oluşturduğunuz tek bir yerle başlayın. Her isteğin aynı davranmasını sağlayacak temel ayarları oraya koyun: varsayılan başlıklar (uygulama sürümü, locale, auth token) ve net bir User‑Agent, zaman aşımı değerlerini bir yerde belirleme (çağrılar arasında dağılmasın), hata ayıklama için açılabilecek loglama ve tek bir yeniden deneme kararı (hatta bu “otomatik yeniden deneme yok” bile olabilir).
Aşağıda yapılandırmayı tek dosyada tutan küçük bir örnek var (kod bloğu içeriği değiştirilmedi):
val okHttp = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.callTimeout(30, TimeUnit.SECONDS)
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.header("User-Agent", "MyApp/${BuildConfig.VERSION_NAME}")
.header("Accept", "application/json")
.build()
chain.proceed(request)
}
.build()
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttp)
.addConverterFactory(MoshiConverterFactory.create())
.build()
Kullanıcı mesajlarına eşleyen merkezi hata işlemi
Ağ hataları sadece “bir istisna” değildir. Her ekran farklı şekilde işliyorsa kullanıcılar rastgele mesajlar görür.
Hataları küçük bir kullanıcı dostu çıktı kümesine eşleyen bir mapper oluşturun: bağlantı yok/uçak modu, zaman aşımı, sunucu hatası (5xx), doğrulama veya auth hatası (4xx) ve bilinmeyen bir durum. Bu, UI kopyasını tutarlı tutar (“Bağlantı yok” vs “Tekrar deneyin”) ve teknik detay sızdırmaz.
Ekran kapanınca isteklere tag atayın ve iptal edin
Kararsız ağlarda çağrılar geç tamamlanıp artık olmayan bir ekranı güncelleyebilir. İptal etmeyi standart kural yapın: bir ekran kapandığında ilgili işler durmalı.
Retrofit ve Kotlin coroutines ile coroutine scope'u iptal etmek (örneğin ViewModel'de) altında yatan HTTP çağrısını iptal eder. Coroutines olmayan çağrılarda Call referansını tutun ve cancel() çağırın. Ayrıca istekleri tag'leyip bir özelliği terk ettiğinizde grup çağrılarını iptal edebilirsiniz.
Arka plan işi UI'ya bağlı olmamalı
Tamamlanması gereken önemli işler (rapor gönderme, bir kuyruğu senkronize etme, bir gönderimi bitirme) UI'ya bağlı olmayan bir planlayıcıda çalışmalıdır. Android'de bunun için genelde WorkManager tercih edilir çünkü daha sonra yeniden deneme yapabilir ve uygulama yeniden başlasa bile devam edebilir. UI işlemlerini hafif tutun ve anlamlıysa daha uzun işleri arka plan işlerine devredin.
Mobil için güvenli önbellekleme kuralları
Önbellekleme yavaş bağlantılarda tekrar indirmeleri azaltıp ekranları anlık hissettirdiği için büyük bir kazançtır. Ancak yanlış zamanda bayat veri gösterirse sorun olur (eski bakiye, güncel olmayan teslimat adresi).
Güvenli yaklaşım: kullanıcı biraz eski olmasında sakınca olan şeyleri önbelleğe alın, para, güvenlik veya son kararı etkileyenleri kesinlikle güncelleyin.
Güvenebileceğiniz Cache-Control temelleri
Çoğu kural birkaç başlıkla özetlenir:
max-age=60: bu süre boyunca önbelleğe alınan cevap tekrar sunucuya sormadan kullanılabilir.no-store: bu cevabı kaydetme (tokenler ve hassas ekranlar için en iyisi).must-revalidate: süresi dolduysa tekrar kullanmadan önce sunucuya doğrulama yapmalısınız.
Mobilde must-revalidate, geçici çevrimdışı bir dönem sonrası “sessizce yanlış” verileri önler. Kullanıcı bir metro yolculuğundan sonra uygulamayı açarsa hızlı bir ekran istersiniz ama aynı zamanda uygulamanın doğrulamayı yapmasını istersiniz.
ETag yenilemeleri: hızlı, ucuz ve güvenilir
Okuma endpointleri için ETag doğrulaması genellikle uzun max-age değerlerinden daha iyidir. Sunucu bir ETag gönderir. Sonraki sefer uygulama If-None-Match başlığı ile bu değeri gönderir. Hiçbir şey değişmediyse sunucu 304 Not Modified döner; bu zayıf ağlarda bile küçük ve hızlıdır.
Bu ürün listeleri, profil detayları ve ayarlar ekranları için iyi çalışır.
Basit bir kural:
- Okuma endpointlerini kısa
max-age+must-revalidateile önbelleğe alın ve mümkünseETagdestekleyin. - Yazma endpointlerini (POST/PUT/PATCH/DELETE) önbelleğe almayın; hep ağda çalıştırın.
- Hassas olan her şey için
no-storekullanın (auth cevapları, ödeme adımları, özel mesajlar). - Statik varlıkları (ikonlar, genel konfigürasyon) daha uzun süre önbelleğe alın; bayatlama riski düşüktür.
Uygulama genelinde önbellekleme kararlarını tutarlı tutun. Kullanıcılar küçük gecikmelerden çok, ekranlar arasındaki tutarsızlıkları fark eder.
İşleri daha kötü hale getirmeyen güvenli yeniden denemeler
Yeniden denemeler kolay bir çözüm gibi görünür ama ters tepki verebilir. Yanlış istekleri yeniden denerseniz ekstra yük, pil tüketimi ve uygulamanın takılı hissetmesi gibi sorunlar çıkar.
İlk olarak sadece geçici olduğu muhtemel hataları yeniden deneyin. Bir bağlantı kopması, bir read timeout veya kısa bir sunucu kesintisi sonraki denemede başarılı olabilir. Kötü bir parola, eksik alan veya 404 yeniden denemeye değmez.
Pratik kurallar:
- Zaman aşımı ve bağlantı hatalarını yeniden deneyin.
- 502, 503 ve bazen 504 için yeniden denemeyi düşünün.
- 4xx hatalarını yeniden denemeyin (408 veya 429 için açık bekleme kuralınız varsa istisna olabilir).
- Zaten sunucuya ulaşmış ve işleniyor olabilecek istekleri yeniden denemeyin.
- Yeniden denemeleri düşük tutun (genelde 1–3 deneme).
Backoff + jitter: yeniden deneme dalgalarını azaltın
Birçok kullanıcı aynı anda bir kesintiyle karşılaşırsa anında yeniden denemeler, kurtarmayı zorlaştıran bir trafik dalgası oluşturabilir. Üssel backoff (her seferinde daha uzun bekleme) ve jitter (küçük rastgele gecikme) kullanın ki cihazlar senkronize şekilde yeniden denemeye başlamasın.
Örnek: yaklaşık 0.5s, sonra 1s, sonra 2s bekleyin ve her adımda yaklaşık +/- %20 rastgelelik ekleyin.
Toplam yeniden deneme süresine sınır koyun
Sınırlama yoksa kullanıcılar dakikalarca spinner içinde takılabilir. Tüm operasyon için maksimum toplam süre seçin (yeniden denemeler ve beklemeler dahil). Birçok uygulama 10–20 saniye civarı bir hedef koyar; sonra durup net bir yeniden deneme seçeneği gösterir.
Ayrıca bağlamla eşleştirin. Bir form gönderiyorsa kullanıcı çabuk bir yanıt ister. Arka plan senkronizasyonuysa daha sonra yeniden denenebilir.
Non-idempotent (tekrar aynı isteğin ikinci bir yazma yaratabileceği) işlemleri otomatik yeniden denemeyin; ya idempotency anahtarı kullanın ya da sunucu tarafı kopya kontrolü sağlayın. Güvenliği garanti edemiyorsanız açıkça başarısız ediniz ve kullanıcının ne yapacağına karar vermesini isteyin.
Kritik işlemler için kopya önleme
Zayıf veya kararsız bağlantıda kullanıcılar iki kez dokunur. OS veya ağ arka planda yeniden deneyebilir. İşlem “bir şey oluşturma” ise (sipariş verme, para gönderme, şifre değiştirme) kopyalar zararlı olabilir.
Idempotency, aynı isteğin tekrar edilmesi durumunda aynı sonucu üretmesi demektir. İstek tekrarlandığında sunucu ikinci bir sipariş yaratmamalı; ilk sonucu tekrar döndürmeli veya “zaten yapıldı” demelidir.
Her kritik deneme için idempotency anahtarı kullanın
Kritik işlemler için kullanıcı denemeyi başlattığında benzersiz bir idempotency anahtarı oluşturun ve istekle gönderin (genelde Idempotency-Key gibi bir başlık veya gövdede bir alan).
Pratik akış:
- Kullanıcı “Öde”ye dokunduğunda UUID tabanlı bir idempotency anahtarı oluşturun.
- Bunu yerelde küçük bir kayıtla saklayın: status = pending, createdAt, istek gövdesi hash'i.
- İsteği anahtar ile gönderin.
- Başarı gelirse status = done yapın ve sunucunun döndürdüğü sonuç ID'sini saklayın.
- Yeniden denemeniz gerekirse aynı anahtarı yeniden kullanın, yeni bir anahtar oluşturmayın.
“Aynı anahtarı yeniden kullanma” kuralı kazara çift ücretleri engelleyen kısımdır.
Uygulama yeniden başlatmaları ve çevrimdışı aralarla başa çıkma
Uygulama istek ortasında kapanırsa sonraki başlatma güvenli olmalı. Idempotency anahtarını ve isteğin durumunu yerel depolamada saklayın (küçük bir DB satırı gibi). Yeniden başlatmada ya aynı anahtarla yeniden deneyin ya da saklı anahtar/sonuç ID ile bir “durum sorgula” endpointini çağırın.
Sunucu tarafında sözleşme net olmalı: aynı anahtar tekrar gelirse ikinci denemeyi reddetsin veya orijinal cevabı döndürsün (aynı sipariş ID'si, aynı makbuz). Sunucu bunu henüz yapamıyorsa istemci tarafı kopya önleme asla tamamen güvenilir olmayacaktır çünkü uygulama isteği gönderdikten sonra ne olduğunu göremez.
Kullanıcıya iyi bir dokunuş: bir deneme beklemedeyse “Ödeme işleniyor” gösterin ve sonuç gelene kadar düğmeyi devre dışı bırakın.
Kazara yeniden gönderimleri azaltan UI desenleri
Yavaş bağlantılar sadece istekleri bozmaz; insanların tıklama şeklini değiştirir. Ekran iki saniye donarsa birçok kullanıcı “hiçbir şey olmadı” diye tekrar düğmeye basar. UI, “tek tıklama”nın ağ kötü olsa bile güvenilir hissettirmesini sağlamalıdır.
Geri alınabilir veya düşük riskli işlemler (bir öğeyi favorileme, taslak kaydetme, mesajı okundu işaretleme) için optimistic UI güvenlidir. Para, stok, geri dönülemez silmeler ve kopya yaratabilecek her şey için confirmed UI daha iyidir.
Kritik işlemler için iyi bir varsayılan: net bir bekleme durumu. İlk tıklamada birincil düğmeyi hemen “Gönderiliyor…” durumuna alın, devre dışı bırakın ve kısa bir açıklama gösterin.
Kararsız ağlarda iyi çalışan desenler:
- Birincil işlemi tıklamadan sonra devre dışı bırakın ve nihai sonuç gelene kadar kapalı tutun.
- Miktar, alıcı, öğe sayısı gibi detayları gösteren görünür bir “Beklemede” durumu gösterin.
- Kullanıcının zaten ne gönderdiğini doğrulayabilmesi için basit bir “Son etkinlik” görünümü ekleyin.
- Uygulama arka plana alınırsa beklemede durumu koruyun.
- Aynı ekranda birden fazla dokunma alanı yerine bir net birincil buton tercih edin.
Bazen istek başarılı olur ama yanıt kaybolur. Bunu kullanıcıyı tekrar denemeye iten bir hatadan ziyade normal bir sonuç gibi ele alın. “Başarısız, tekrar dene” demek yerine “Henüz emin değiliz” gösterin ve güvenli bir sonraki adım sunun (örn. “Durumu kontrol et”). Durum kontrolü mümkün değilse yerel bekleme kaydını tutun ve bağlantı geri geldiğinde güncelleyeceğinizi söyleyin.
“Tekrar dene”yi yalnızca aynı istemci tarafı istek ID'si veya idempotency anahtarı ile güvenli şekilde tekrarlanabiliyorsa gösterin.
Gerçekçi örnek: kararsız bir checkout gönderimi
Bir müşteri sinyali zayıf bir tren yolculuğunda. Sepete ürün ekler ve Öde'ye dokunur. Uygulama sabırlı olmalı ama iki sipariş yaratmamalıdır.
Güvenli bir sıra şöyle görünür:
- Uygulama istemci tarafında bir deneme ID'si oluşturur ve checkout isteğini bir idempotency anahtarı ile gönderir (ör. sepetle ilişkili bir UUID).
- İstek net bir connect zaman aşımını, sonra daha uzun bir read zaman aşımını bekler. Tren tünele girer ve çağrı zaman aşımına uğrar.
- Uygulama yalnızca sunucudan cevap hiç alınmamışsa kısa bir gecikme sonra bir kez yeniden dener.
- Sunucu ikinci isteği aldığında aynı idempotency anahtarını görür ve yeni bir sipariş oluşturmak yerine orijinal sonucu döndürür.
- Uygulama başarı yanıtını aldığında (yeniden denemeden gelmiş olsa bile) son onay ekranını gösterir.
Önbellekleme katı kurallara uyar. Ürün listeleri, teslimat seçenekleri ve vergi tabloları kısa süre önbelleğe alınabilir (GET istekleri). Checkout gönderimi (POST) asla önbelleğe alınmaz. HTTP önbelleği kullansanız bile bunu gezinme için sadece okuma yardımı olarak düşünün, ödeme “hatırlaması” için değil.
Kopya önleme ağ ve UI seçimlerinin karışımıdır. Kullanıcı Öde'ye dokunduğunda düğme devre dışı olur ve ekran “Sipariş gönderiliyor...” tek bir İptal seçeneği ile gösterilir. Ağ kaybolursa “Hâlâ deniyoruz” durumuna geçer ve aynı deneme ID'sini korur. Kullanıcı zorla kapatıp yeniden açarsa uygulama, onları tekrar ödemeye zorlamak yerine o ID ile sipariş durumunu sorgulayarak devam edebilir.
Hızlı kontrol listesi ve sonraki adımlar
Ofis Wi‑Fi'sinde “çoğunlukla iyi” olan uygulamanız tren, asansör veya kırsal alanlarda dağılıyorsa bunu bir yayın engeli olarak değerlendirin. Bu iş usta koddan çok tekrar edilebilir net kurallar ile ilgilidir.
Yayın öncesi kontrol listesi:
- Endpoint türüne göre zaman aşımı ayarlarını yapın (giriş, feed, yükleme, checkout) ve kısıtlanmış/yüksek gecikmeli ağlarda test edin.
- Yeniden denemeyi sadece gerçekten güvenliyse kullanın ve backoff ile sınırlandırın (okumalar için birkaç deneme, yazmalar için genelde yok).
- Her kritik yazma için bir idempotency anahtarı ekleyin (ödemeler, siparişler, form gönderimleri) ki yeniden deneme veya çift tıklama kopya yaratamasın.
- Önbellekleme kurallarını açıkça yapın: ne bayat sunulabilir, ne her zaman taze olmalı, ne asla önbelleğe alınmamalı.
- Durumları görünür yapın: beklemede, başarısız ve tamamlandı farklı görünmeli ve uygulama yeniden başlatıldığında tamamlanan eylemleri hatırlamalı.
Eğer bunlardan biri “daha sonra karar verilecek” ise ekranlar arasında rastgele davranışlarla karşılaşırsınız.
Kalıcı hale getirmek için sonraki adımlar
Bir sayfalık bir ağ politikası yazın: endpoint kategorileri, zaman aşımı hedefleri, yeniden deneme kuralları ve önbellekleme beklentileri. Bunu tek bir yerde (interceptorlar, paylaşılan bir client factory veya küçük bir sarmalayıcı) uygulatın ki her takım üyesi varsayılan olarak aynı davranışı elde etsin.
Sonra kısa bir kopya testi yapın. Bir kritik işlemi (ör. checkout) seçin, donmuş bir spinner simüle edin, uygulamayı zorla kapatın, uçak modunu açıp kapatın ve düğmeye tekrar basın. Güvenli olmadığını kanıtlayamıyorsanız kullanıcılar er ya da geç onu bozmanın bir yolunu bulacaktır.
Eğer aynı kuralları backend ve istemciler arasında el ile yazmadan uygulamak isterseniz, AppMaster (appmaster.io) üretime hazır backend ve yerel mobil kaynak kodu oluşturmakta yardımcı olabilir. Yine de anahtar politika: idempotency, yeniden denemeler, önbellekleme ve UI durumlarını bir kez tanımlayın ve tüm akış boyunca tutarlı şekilde uygulayın.
SSS
Her ekranda ve işlemde “doğru”nun ne olduğunu tanımlamakla başlayın; özellikle bir kereden fazla çalışmaması gereken ödemeler veya siparişler gibi işlemler için kuralları netleştirin. Kurallar netleşince zaman aşımı, yeniden deneme, önbellekleme ve UI durumlarını kütüphane varsayımlarına dayanmak yerine bunlara göre ayarlayın.
Kullanıcılar genellikle sonsuz yüklenme göstergeleri, uzun beklemeden sonra gelen hatalar, ikinci denemede çalışan işlemler veya iki sipariş/duble ücretlendirme gibi kopya sonuçlar görürler. Bunlar çoğunlukla belirsiz yeniden deneme ve “beklemede vs başarısız” kurallarından kaynaklanır, yalnızca kötü sinyalden değil.
Connect timeout bağlantı kurulurken (DNS/TCP/TLS) ne kadar bekleyeceğinizi, write timeout isteğin gövdesini gönderirken (yüklemeler) ne kadar bekleyeceğinizi, read timeout ise isteği gönderdikten sonra sunucudan veri gelmesini ne kadar bekleyeceğinizi belirtir. Düşük riskli okumalar için daha kısa, kritik gönderimler için daha uzun read/write süreleri makul bir başlangıçtır; ayrıca UI’da bir üst sınır gösterin ki kullanıcı sonsuz beklemek zorunda kalmasın.
Evet — eğer tek bir şey ayarlayabiliyorsanız, tüm operasyonu uçtan uca sınırlayan callTimeout kullanın ki “sonsuz” beklemeler önlensin. Yüklemeler ve yavaş cevap gövdeleri için kontrolü iyileştirmek üzere ayrıca connect/read/write zaman aşımı değerleri de katmanlayın.
Öncelikle bağlantı kopmaları, DNS sorunları ve zaman aşımı gibi geçici hataları yeniden deneyin; bazen 502/503/504 gibi sunucu hatalarını da yeniden denemek mantıklıdır. 4xx hata kodlarını yeniden denemeyin (408 veya 429 dışında açık bekleme kuralınız yoksa). Yazma işlemlerini sunucuya ulaşıp ulaştığı belli olabilecek durumlarda otomatik yeniden denemeyin; aksi halde kopyalar oluşabilir.
Az sayıda yeniden deneme (çoğunlukla 1–3) ile üssel backoff ve küçük rastgele sapma (jitter) kullanın ki birçok cihaz aynı anda yeniden denemeye başlamasın. Ayrıca tüm yeniden denemeler için bir toplam zaman üst sınırı belirleyin, böylece kullanıcı uzun bir spinner içinde takılmaz.
Idempotency, aynı isteğin tekrar edilmesinin ikinci bir sonuç üretmemesi anlamına gelir: çifte tıklama veya yeniden deneme ikinci bir ücretlendirme ya da ikinci sipariş yaratmaz. Kritik işlemler için her deneme başında bir idempotency anahtarı gönderin ve yeniden denemelerde aynı anahtarı tekrar kullanın, böylece sunucu orijinal sonucu döndürebilir.
Kullanıcı işlemi başlattığında benzersiz bir anahtar oluşturun, lokal olarak küçük bir “beklemede” kaydıyla saklayın ve istekle birlikte gönderin. Yeniden deneme veya uygulama yeniden başlatıldığında aynı anahtarı kullanın; böylece durumu sorgulayabilir veya güvenli şekilde yeniden deneyebilirsiniz. Anahtarı uygulama içinde saklamak, uygulama öldüğünde bile güvenliği sağlar.
Sadece biraz eski olmasında sakınca olmayan verileri önbelleğe alın; para, güvenlik ve son kararları etkileyen veriler için her zaman taze kontrol yapın. Okumalar için kısa tazelik + yeniden doğrulama ve ETag tercih edin; yazma isteklerini hiç önbelleğe almayın; hassas cevaplar için no-store kullanın.
Birincil düğmeyi ilk tıklamadan sonra devre dışı bırakın, hemen “Gönderiliyor…” durumunu gösterin ve arka plana alınsa bile beklemede durumunu koruyun. Yanıt kaybolabileceği durumlarda kullanıcıyı tekrarlamaya itmek yerine “Henüz emin değiliz” gibi güvenli bir durum gösterin ve durum denetimi gibi güvenli bir sonraki adım sunun.


