Tüm makaleler
Deep dive8 dk okuma

Hem Apple hem de Google aynı iadeyi sunucunuza birden fazla kez teslim edebilir ve her birine göre işlem yaparsanız yinelenen iade bildirimleri size pahalıya patlar

Apple bir iade bildirimini beş kereye kadar yeniden dener ve Google Play, en az bir kez teslimat sağlayan Pub/Sub üzerinde çalışır, bu yüzden aynı iade sunucunuza birden fazla kez ulaşabilir. Bakiyeyi düşürmeden ya da API kotasını iki kez harcamadan yinelenen iade bildirimlerini nasıl ele alacağınız burada.

Karanlık bir masada üst üste dizilmiş, biri kenara çekilmiş çok sayıda özdeş kağıt zarf, sunucunuza ulaşan yinelenen iade bildirimlerini temsil ediyor

Önemli noktalar

  • Apple, sunucunuz 200 ile 206 arasında bir HTTP durumuyla yanıt vermediğinde bir App Store Server Notification V2 bildirimini beş kez yeniden dener, son denemeden 1, 12, 24, 48 ve 72 saat sonra. İlk deneme dahil, bir iade altı kereye kadar gelebilir.
  • Her gerçek Apple yeniden denemesi aynı notificationUUID değerini taşır, bu yüzden işlem kimliği değil, o alan sizin yineleme giderme anahtarınızdır.
  • Google Play'in Real-time Developer Notifications bildirimleri, en az bir kez teslimat garanti eden ve sıralama garantisi olmayan Cloud Pub/Sub üzerinde çalışır, bu yüzden aynı mesaj iki kez ya da sırasız gelebilir. Google, herhangi bir şeyi işlemeden önce messageId değerinin benzersizliğini kontrol etmenizi söyler.
  • Apple'ın periyodik CONSUMPTION_REQUEST bildirimleri yeniden deneme değildir. Apple, açık iade penceresi boyunca her biri farklı bir notificationUUID taşıyan yenilerini göndermeye devam eder, bu yüzden notificationUUID üzerinden yineleme gidermek her birini doğru şekilde korur.
  • Aynı Apple transactionId birden fazla karar taşıyabilir, örneğin bir REFUND_DECLINED ardından daha sonra bir REFUND, bu yüzden yalnızca işlem kimliği üzerinden yineleme gidermek ihtiyacınız olan ayrı bir olayı atar.
  • Bir yinelemeyi 4xx ya da 5xx döndürerek reddetmek yalnızca mağazanın onu yeniden denemesine yol açar. Yineleme gidermeyi kendi veritabanınızın içinde yapın ve her zaman bir başarı durumu döndürün.
  • Idempotent olmayan bir iade işleyicisi, ikinci teslimatta işlemi ikinci kez yapar. Bakiyeyi iki kez düşürür, bir ödemeyi iki kez geri alır ya da zaten kapattığı bir iadeyi yeniden kontrol ederek ücretli Play Developer ve App Store Server API kotasını harcar.

Sunucunuz aynı iade olayını birden fazla kez alacak ve her iki mağaza da bunu bilerek böyle tasarladı. Uç noktanız düzgün yanıt vermediğinde Apple bir App Store Server Notification bildirimini beş kereye kadar yeniden dener. Google Play, Real-time Developer Notifications bildirimlerini, en az bir kez teslimat vaat eden ve sıralama hakkında hiçbir şey vaat etmeyen Cloud Pub/Sub üzerinden teslim eder. Yani soru asla bir yinelemenin gelip gelmeyeceği değildir. Aynı iadeyi ikinci kez gördüğünde kodunuzun ne yaptığıdır. Bunu yanlış yapın, bakiyeyi iki kez düşürürsünüz, bir ödemeyi iki kez geri alırsınız ya da zaten kapattığınız bir iadeyi yeniden kontrol ederek ücretli API kotasını harcarsınız. Yinelenen iade bildirimlerinin size gerçekte nasıl ulaştığı, hangi tekrarların gerçek yineleme olduğu ve hangilerinin yalnızca öyle göründüğü ve ikinci teslimatın bedava olması için bunları nasıl ele alacağınız burada.

Bir iade bildirimi en az bir kez teslim edilir, bu tam olarak bir kez ile aynı şey değildir

Her iki mağaza da teslim edilmiş bir bildirimi, ateşleyip unuttukları tek bir atış olarak değil, yerine getirmeye çalışmaya devam ettikleri bir söz olarak görür. Bu güvenilirlik açısından iyidir, çünkü bir dağıtım sırasında kaçırdığınız bir bildirim size daha sonra yine de ulaşır. Doğruluk açısından bir tuzaktır, çünkü olayı eninde sonunda almanızı garanti eden mekanizma, bazen onu iki kez almanızı da garanti eder. İşleyicinizin idempotent olması gerekir, yani bir iadenin ikinci ve üçüncü teslimatları, ilkinin zaten değiştirmediği hiçbir şeyi değiştirmez.

Apple üç gün boyunca beş kez yeniden dener

Apple bir App Store Server Notification V2 gönderdiğinde, sunucunuzun 200 ile 206 arasında bir HTTP durumuyla yanıt vermesini bekler. Bunun dışında herhangi bir şey, bir 4xx ya da bir 5xx, Apple'a teslimatın başarısız olduğunu söyler ve Apple yeniden dener. Program sabittir: beş yeniden deneme, önceki denemeden 1, 12, 24, 48 ve 72 saat sonra. İlk deneme dahil, bir iade olayı yaklaşık bir haftaya yayılarak altı kereye kadar gelebilir. Bu yeniden denemelerin her biri aynı notificationUUID değerini taşır. O alan sizin yineleme giderme anahtarınızdır. Bir notificationUUID değerini zaten kaydettiyseniz, elinizde tuttuğunuz teslimat bir tekrardır ve doğru yanıt yeni hiçbir şey kaydetmemek ve yine de 200 döndürmektir.

Google Play, en az bir kez vaat eden ve sıralama hakkında hiçbir şey söylemeyen Pub/Sub üzerinde çalışır

Google Play'in Real-time Developer Notifications bildirimleri bir Cloud Pub/Sub konusuna yayınlanır. Pub/Sub'ın teslimat garantisi en az bir kezdir ve hiçbir sıralama garantisi vermez. Bu, aynı mesajın uç noktanıza birden fazla kez teslim edilebileceği ve aynı satın alma için iki mesajın sırasız gelebileceği anlamına gelir. Google'ın kendi rehberliği açıktır: base64 data alanını açın, messageId değerini okuyun ve herhangi bir şeyi işlemeden önce bunu daha önce görmediğinizi kontrol edin. Yinelenen bir messageId atladığınız bir tekrardır. Tek bir satın alma hakkındaki iki farklı bildirim yine de aynı kayda inmelidir, bu yüzden saklanan durumunuzu purchaseToken üzerine de anahtarlayın ve daha sonraki bir olayın, daha erken birinin oluşturduğu satırı güncellemesine izin verin.

PlatformTeslimat modeliYineleme giderme anahtarıBaşarı sinyaliOnaylamazsanız
App Store Server Notifications V26 denemeye kadar: ilki, artı 1, 12, 24, 48, 72 saatte 5 yeniden denemenotificationUUIDHTTP 200 ile 206 arasıApple sabit programda yeniden dener, sonra durur
Pub/Sub üzerinden Google Play RTDNEn az bir kez, sıralama garantisi yokPub/Sub messageId, purchaseToken üzerinden varlık anahtarlıPush'a HTTP 200 ya da açık bir onayOnay son tarihi dolduktan sonra Pub/Sub yeniden gönderir

Yineleme olmayan tekrarlar

Gördüğünüz birine benzeyen her bildirim bir yeniden deneme değildir. İki Apple davranışı, bir satın almayı paylaşan ama her biri işlenmesi gereken gerçekten yeni olaylar gönderir ve bunları saf bir yineleme gidermeyle birleştirmek ihtiyacınız olan bilgiyi atar.

Apple yeni CONSUMPTION_REQUEST gönderir, yeniden deneme değil

Bir tüketilebilir üzerinde açık bir iade talebi sırasında Apple tek bir CONSUMPTION_REQUEST gönderip beklemez. İade kapanana kadar tüm açık iade penceresi boyunca periyodik olarak yenilerini gönderir. Apple çalışanları bunların yeniden deneme olmadığını doğruladı ve ipucu, yineleme gidermek için kullandığınız alandadır: her yeni CONSUMPTION_REQUEST farklı bir notificationUUID taşır. Yani notificationUUID üzerine anahtarlanmış bir yineleme giderme doğru şeyi otomatik olarak yapar. Gerçek yeniden denemeleri birleştirir ve her ayrı istemi korur. Yapmamanız gereken şey, işlem kimliği ve bildirim türü üzerinden yineleme gidermektir, çünkü bu ilkinden sonraki her CONSUMPTION_REQUEST bildirimini susturur ve atladıklarınızda size 12 saatlik kanıt penceresine mal olur.

Bir işlem birden fazla karar taşıyabilir

Tek bir transactionId, ömrü boyunca birden fazla iade sonucu üretebilir. Apple aynı işlem için bir REFUND_DECLINED ve ardından daha sonra bir REFUND gönderebilir ve geliştiriciler tek bir işlem kimliği için üç ya da daha fazla iade ile ilgili bildirim aldıklarını bildiriyor. Her biri kendi notificationUUID değerine sahip ayrı bir olaydır. Yineleme giderme anahtarınız işlem kimliğiyse, ikinci karar birincinin bir yinelemesi gibi görünür ve iadenin sonunda verildiğini asla öğrenemezsiniz. İşlem kimliği olayları gruplar. Onları tanımlamaz.

Bir konveyör hattından yinelenen bir paketi kaldırıp yan bir kutuya bırakan robotik bir kavrayıcı, tekrarlanan iade bildirimlerinin yineleme gidermesini temsil eden bir görsel

Bir yinelemenin size gerçekte neye mal olduğu

Bir iade bildirimi bir durum ışığı değildir. Gerçek eylemleri tetikler: erişimi iptal edersiniz, bir tüketilebilir bakiyeyi düşürürsünüz, bir içerik üreticisi ödemesini geri alırsınız, durumu onaylamak için App Store Server API ya da Play Developer API'yi çağırırsınız. Bunlardan herhangi birini bir yineleme üzerinde ikinci kez çalıştırın ve maliyet gerçektir.

Parayı takip edin. Erişimi iki kez iptal etmek zararsızdır, çünkü erişim zaten gitti. Bir bakiyeyi iki kez düşürmek zararsız değildir: bir madeni para paketi satın alıp iade eden bir kullanıcı, destek ekibinizin daha sonra elle çözmesi gereken negatif bir bakiyeye sürüklenebilir. Bir ödemeyi iki kez geri almak, zaten bir kez iade ettiğiniz parayı geri çeker ve artık bir içerik üreticisine bir özür ve bir düzeltme borçlusunuz. Ve bir mağaza API'sine karşı yeniden işlediğiniz her yineleme, Google'ın açıkça korumanız için uyardığı kotayı harcar, bu yüzden bir kesinti sırasında bir Pub/Sub yeniden teslimat patlaması, sizi tam da en az kaldırabileceğiniz gün oran sınırlamasına itebilir.

İade kanıt pencereleri Apple tarafında riski yükseltir. Saf bir yineleme giderme, Apple'ın açık iade penceresi boyunca gönderdiği tekrarlanan CONSUMPTION_REQUEST bildirimlerini susturursa, yanıt vermeniz gerekeni kaçırabilirsiniz ve 12 saat içinde yanıt vermediğiniz bir CONSUMPTION_REQUEST, Apple'ın çoğu zaman varsayılan olarak verdiği bir iadedir. Bu bir çift ücretlendirme değildir. Bu kayıp bir satış artı satın almayı teslim etmek için zaten harcadığınız işlem gücü, API çağrıları, depolama ve ödemelerdir, bunların hiçbirini iade geri getirmez.

Hata moduNeyin yanlış gittiğiNeye mal olduğu
Yinelenen bir REFUND üzerinde bakiyeyi yeniden düşürmekKullanıcının tüketilebilir bakiyesi eksiye düşerUzlaştırmak için elle destek süresi ve kötü bir müşteri deneyimi
Bir ödemeyi iki kez geri almakZaten bir kez iade ettiğiniz parayı geri çekersinizBir içerik üreticisi düzeltmesi ve bir muhasebe temizliği
Bir mağaza API'sine karşı yeniden işlemekYinelenen çağrılar Play Developer ya da App Store Server API kotasını harcarYeniden teslimata neden olan kesinti sırasında oran sınırlaması
CONSUMPTION_REQUEST bildirimlerini aşırı yineleme gidermekAyrı bir iade istemini sahte bir yineleme olarak atarsınızKaçırılan bir 12 saatlik pencere, böylece Apple iadeyi varsayılan olarak verir

Yinelenen iade bildirimlerini iki kez işlem yapmadan nasıl ele alırsınız

Kalıp her iki mağazada da aynıdır, farklı bir anahtarla. Teslimatı kaydedin, işlem yapmadan önce anahtarı kontrol edin, bir kez işlem yapın ve mağazaya her zaman onu aldığınızı söyleyin.

  • Mağazanın teslimat kimliği üzerinden yineleme giderin, işlem üzerinden değil. Apple için notificationUUID ve Google Play için Pub/Sub messageId kullanın. Eşzamanlı bir yinelemenin iki kez işlem yapmak yerine yarışı kaybetmesi için onu benzersiz bir kısıtlamayla saklayın.
  • Aşağı akış eylemini kendi koşullarında idempotent yapın. Teslimat kimliği üzerine anahtarlamak yeniden işlemeyi durdurur, ama etkiyi de öyle yazın ki iptal, düşürme ya da geri alma önce mevcut durumu kontrol etsin ve iki kez çalıştırmak güvenli olsun.
  • Önce kalıcı kılın, sonra onaylayın. 200 döndürmeden ya da Pub/Sub mesajını onaylamadan önce olayı veritabanınıza yazın. Önce onaylar ve yazma başarısız olursa, mağaza mesajı teslim edilmiş sayar ve onu bir daha asla göndermez, ve artık onu tamamen kaybettiniz.
  • Bir yineleme için bile her zaman bir başarı durumu döndürün. Apple için 200 ile 206 arası, Google için Pub/Sub push'a bir 200. Bir tekrarı hatayla reddetmek yalnızca mağazanın onu yeniden denemesine yol açar.
  • Varlık üzerinde gruplayın, olay üzerinde tanımlayın. Sırasız teslimatların tek bir satırı güncellemesi için saklanan satın alma durumunuzu purchaseToken ya da originalTransactionId üzerine anahtarlayın, ama her notificationUUID ya da messageId değerine kendi olayı olarak davranın, çünkü bir satın alma haklı olarak birkaç tane üretir.

İade webhook'unuza güvenmeden önce kısa bir kontrol listesi

  • Apple teslimatları notificationUUID üzerinden yineleme giderilir ve bir tekrar yeni hiçbir şey yazmaz ama yine de 200 döndürür.
  • Google Play teslimatları, herhangi bir işlemeden önce kontrol edilen Pub/Sub messageId üzerinden yineleme giderilir.
  • Satın alma durumu, sırasız olayların tek bir kayda inmesi için purchaseToken ya da originalTransactionId üzerine anahtarlanır.
  • Her iade yan etkisi, iptal, düşürme ya da geri alma, birden fazla kez çalıştırmak için güvenlidir.
  • İşleyiciniz olayı onaylamadan önce yazar, asla sonra değil.
  • Tekrarlanan CONSUMPTION_REQUEST bildirimleri, yineleme olarak değil ayrı istemler olarak ele alınır, böylece hiçbir açık iade penceresi atlanmaz.

Kendi webhook'unuzdan bilerek bir yineleme geçirin ve ikinci kez hiçbir şeyi değiştirmediğini izleyin. Tüm test budur. İki kez vurulmaya güvenli bir iade işleyicisi, bir mağazanın onu altı kez vurmaya karar verdiği anda endişelenmeyi bırakabileceğiniz bir işleyicidir.

Sık sorulan sorular

Sunucum neden aynı App Store iade bildirimini birden fazla kez alıyor?
Çünkü Apple, sunucunuz 200 ile 206 arasında bir HTTP durumuyla yanıt vermediğinde bir App Store Server Notification V2 bildirimini beş kereye kadar yeniden dener, son denemeden 1, 12, 24, 48 ve 72 saat sonra. Her yeniden deneme aynı notificationUUID değerini taşır, bu yüzden onu tanıyıp atlayabilirsiniz.
App Store Server Notifications için yineleme gidermede hangi alanı kullanmalıyım?
notificationUUID kullanın. Gerçek bir yeniden deneme her zaman aynı notificationUUID değerini tekrarlar, oysa gerçekten yeni her olay, her yeni CONSUMPTION_REQUEST dahil, farklı bir tane alır, bu yüzden notificationUUID üzerinden yineleme gidermek ayrı olayları atmadan tekrarları atlar.
Tekrarlanan CONSUMPTION_REQUEST bildirimleri göz ardı etmem gereken yinelemeler mi?
Hayır. Apple, açık iade penceresi boyunca periyodik olarak yeni CONSUMPTION_REQUEST bildirimleri gönderir ve Apple çalışanları bunların yeniden deneme olmadığını doğrular. Her birinin kendi notificationUUID değeri vardır, bu yüzden her birini işleyin. Onları atmak, Apple'ın size yanıt vermeniz için verdiği 12 saatlik pencereyi kaçırma riski taşır.
Google Play Real-time Developer Notifications bildirimlerini nasıl yineleme giderime tabi tutarım?
İşlem yapmadan önce her bildirimden Pub/Sub messageId değerini okuyun ve zaten işlediklerinizle karşılaştırın, çünkü Pub/Sub en az bir kez teslim eder ve aynı mesajı birden fazla kez gönderebilir. Google, yinelenen işlemeden ve boşa harcanan API kotasından kaçınmak için bunu açıkça önerir.
Yinelenen bir iade bildirimini reddetmek için bir hata mı döndürmeliyim?
Hayır. Bir 4xx ya da 5xx döndürmek mağazaya teslimatın başarısız olduğunu söyler, bu yüzden yine de yeniden dener. Yineleme gidermeyi kendi veritabanınızın içinde yapın ve her zaman bir başarı durumu döndürün, Apple için HTTP 200 ile 206 arası ya da Google Play push için bir 200 onayı.

Kaynaklar ve ek okumalar

RefundHalt

App Store ve Google Play için geri ödeme otomatik pilotu

Okumaya devam edin

Bir sonraki geri ödeme talebi şimdiden yolda.

İtiraz edemediğiniz bir geri ödemeyle ilgili başka bir destek e-postasını okumak için gereken sürede RefundHalt'ı kurun.