Hoppa till huvudinnehåll

Varför köpa retries skapa dubbla rättigheter och hur man testar dem

Original Persistium inköpsledger diagram som visar en avsikt, en hållbar rekord och en replay-safe entitlement beslut.

Hur man modellerar inköp av avsikt, okända begå resultat, retries och rättighet unikhet så ett köp kan säkert hämtas utan att bevilja två gånger.

En retry är inte ett andra köpbeslut

Inköpsflöden misslyckas i utrymmet mellan ett externt betalningsevenemang och ett in-game-bidrag. Ett kvitto kan komma två gånger. En nätverksförfrågan kan timeout efter att servern begått tillstånd men innan klienten fick svaret. En process kan krascha efter att ha reserverat en transaktion men innan du beviljar valuta. På omstart kan den säkraste åtgärden vara att retry arbete som avbröts. Om systemet behandlar varje retry som tillstånd att bevilja, dubbla rättigheter är en normal konsekvens av återhämtning.

Den användbara distinktionen är avsikt kontra bidrag. Avsikten är begäran om att få en specifik produkt under en specifik transaktionsidentitet. Grant är den hållbara spelsidan resultat: rättighet ägande, en valuta delta, en lager objekt, eller en prenumerationsperiod. Samma avsikt kan levereras, queried, retried, eller återlämnas många gånger. Det bör fortfarande lösa ett bidrag beslut.

Detta är ett ingenjörsmönster, inte en plattformsspecifik garanti. Olika butiker, betalningsleverantörer och spelbackends exponerar olika kvitto, bekräftelse och återbetalningsbeteende. Anta inte att ett kvitto bevisar ett bidrag, eller att ett erkännande bevisar att spelaren såg ett objekt. Bygg serversidan rekord så att spelet kan ange vad det vet och återhämta sig säkert när ett externt resultat är ofullständigt eller försenat.

Ge varje köp avsikt en stabil nyckel

En idempotensnyckel binder upprepade leveransförsök till ett beslut. Det kan härröra från en betrodd plattformstransaktionsidentifierare när den identifieraren är tillgänglig och verifierad, eller det kan utfärdas av en server innan ett köp börjar och kopplas senare till betrodd kvittoinformation. Nyckeln måste vara stabil över retries. Skapa en ny slumpmässig nyckel varje gång klienten trycker på "återställning" skapar helt enkelt flera transaktioner som råkar likna.

Lagra tillräckligt med sammanhang med nyckeln för att avvisa felmatcher: spelar- eller kontoomfattning, produktidentitet, förväntad kvantitet eller rättighetsform, källkanal, fick tid, verifieringsstatus och ett tillstånd som väntande, förkastat eller behovsgranskning. Håll känsligt kvittomaterial ur vanliga loggar. Om råleverantörsbelastningar behöver kort lagring för ett verifierat återhämtningsflöde, skydda dem separat och göra deras åtkomst avsiktlig.

Datamodellen behöver också en unik gräns. För en icke-konsumerbar rätt kan unikhet vara konto plus produkt-ID. För valuta är unikhet vanligtvis huvudboken eller bidragstransaktionen snarare än den nuvarande balansen. För förbrukningsvaror kan en betrodd transaktionsidentifierare vara unik även när produkt-ID upprepar. Definiera nyckeln innan kodning av retrypolicyn; annars kan två delsystem deduplicera mot oförenliga identiteter.

Modell det okända begåvningsresultatet

Det svåra resultatet är inte en ren framgång eller ett rent misslyckande. Det är "okänt": klienten vet inte om servern begick bidraget. En timeout, anslutningsåterställning, processomstart eller serviceavbrott kan producera detta tillstånd. Det säkra klientbeteende är att be om transaktionsstatus eller retry samma avsikt. Det säkra serverbeteendet är att leta upp den avsikten och returnera det hållbara beslutet snarare än att tillämpa en annan mutation.

Gör inte klientens visningstillstånd auktoritativ. En spinnare som försvinner, en lokal kvitto cache, eller en optimistisk balansförändring kan förbättra upplevelsen, men det kan inte bestämma om kontot äger en rättighet. Server myndighet innebär att servern verifierar den accepterade transaktionen enligt produktens förtroende gräns, begår varaktiga rekord en gång och returnerar det aktuella tillståndet när de ställs igen.

Ursprungligt inköpssekvensdiagram som visar upprepade leveransförsök konvergerar på en huvudbok och ett beslut om rättighet.
Retries and receipt releverans lösa mot samma varaktiga inköp avsikt snarare än att skapa nya bidrag.

Sekvensen bör göra partiell slutförandepolicy synlig. Till exempel: ta emot avsikt, validera betrodda inköpsbevis, skapa eller ladda den hållbara huvudboken, begå rättigheten eller valutamutationen, markera det rekord som beviljats, bekräfta extern leverans när det är lämpligt, sedan returnera resultatet. Om processen stannar mellan två steg, kan en återställningsarbetare eller senare statusfråga återupptas från den hållbara rekordet. Den exakta beställningen beror på den externa leverantören och spelarkitekturen, men det enda bidraget identiteten inte.

Skydda rättighet och valutainvarianter

En idempotensnyckel förhindrar replay av en avsikt; det gör inte automatiskt varje biverkning korrekt. Definiera de invarianter ett bidrag måste bevara. En icke-konsumerbar rätt visas högst en gång för kontot och produkten. Ett valutabidrag har en huvudbok med en transaktionsnyckel, ett känt delta och en resulterande balans som matchar summan av giltiga poster. Inventory ger lydiga stack, kapacitet och objektdefinitionsregler. En prenumerationsperiod sträcker sig inte två gånger eftersom bekräftelsen slutpunkten två gånger.

Gör den invarianta kontrolldelen av samma varaktiga operation som begår bidraget. En läsning följt av en senare skriva kan tävla under samtidig leverans. Två arbetstagare kan både observera "inte ägt" och båda bidraget. Använd transaktionsförvaring, jämföra-och-set semantik, en serielliserad kontomutation väg, eller en annan explicit konkurrerande primitiv lämpad för databutiken. Den viktiga egenskapen är att beslutet och dess markör inte kan självständigt vinnas av två försök.

För spel med en in-memory runtime, skiljer hållbar framgång från presentationen. Servern kan uppdatera en spelares synliga balans efter den hållbara huvudboken begår, men den synliga uppdateringen är inte beviset. På återanslutning eller omstart, bygga upp det presenterade tillståndet från den hållbara kontoposten. Det gör en försenad klientrespons obekväm snarare än ekonomiskt osäker.

Testkrascher, omstarter och återleverans avsiktligt

Börja med ett deterministiskt scenario. Skapa ett konto, en produkt, en känd startbalans eller rättighetsuppsättning och en stabil transaktionsnyckel. Kör flödet, injicera sedan ett misslyckande efter varje namngiven gräns: efter mottagandet, efter ledger skapande, efter rättighet mutation, efter statusmarkering, efter extern bekräftelse, och efter svaret är förberedd. Starta den relevanta arbetstagaren eller processen, retry samma nyckel och hävda det slutliga hållbara tillståndet.

Det förväntade resultatet bör vara specifikt. En retry kan returnera "redan beviljas" med det ursprungliga resultatet, återuppta en väntande operation, avvisa en missmatchad nyttolast eller hålla ett rekord för granskning. Det bör inte lägga till en andra lager objekt, tillämpa en andra valuta delta, eller dölja det okända tillståndet med en fabricerad framgång. Fånga klassificeringen i testresultatet så en senare refaktor kan inte vända ett avsiktligt håll i en oavsiktlig dubblett.

Använd kvitto återleverans i samma scenario. Leverera den exakt betrodda transaktionen två gånger, sedan leverera den efter en omstart, sedan leverera den tillsammans med en duplicerad klient retry. Den resulterande huvudboken och kontotillståndet bör vara identisk med en leverans fallet. Om produkten tillåter upprepa inköp, kör samma sekvens med två genuint distinkta transaktionsidentiteter för att bevisa systemet inte överdoppliceras av produkt ID ensam.

Håll gränserna ärliga

Testning kan bara bevisa de interaktioner du utför. Ett simulerat leverantörssvar kan validera din statsmaskin, men det är inte bevis för att varje produktionsleverantörskant beter sig exakt på samma sätt. Ett körbart test mot en sandlåda kan ge förtroende för den integrationen, men ändå har olika operativa förhållanden från en levande butik.

Förtroendegränsen bör också vara tydlig. En klient bör inte lämna in ett godtyckligt belopp, produkt-ID eller "verifierad" flagga och få ett bidrag. Ingångar är otillförlitliga tills servern validerar dem mot relevant konfiguration och köpbevis. Om validering inte kan slutföra, hålla avsikten i väntan eller avvisa den med en återställningsbar kategori. Låt inte en retry-kö bli en bypass runt verifiering.

Sekretess gäller för denna testdisciplin. Fastigheter bör använda syntetiska transaktionsdata. Loggar bör referera till en säker testidentifierare, inte ett rå kvitto eller kontonamn. En produktionsincident kan kräva begränsade bevis, men rutintestsviten ska aldrig bli en andra betalningsdatabutik.

Praktisk checklista

  • Separat en stabil inköp avsikt från det senare spelsidan bidraget.
  • Använd en idempotensnyckel över timeouts, retries, omstarter och kvitto återleverans.
  • Bind nyckeln till kontot, produkten eller rättighetsformen och betrodd källkontext.
  • Definiera hållbara tillstånd som väntande, engagerade, avvisade och behovsgranskning.
  • Verkställa rättighet unikhet och valuta-ledger invarianter inom samma valutagräns som bidraget.
  • Injicera misslyckanden efter varje statsövergång, sedan starta om och retry samma avsikt.
  • Test duplicera leverans och legitima upprepade inköp separat.
  • Rapportera okända resultat ärligt; förvandla inte en timeout till en uppfunnen framgång.
  • Håll kvittoliknande fixturer och testloggar syntetiska och redigerade.

Ofta ställda frågor

Är ett unikt kvitto-ID tillräckligt för idempotens?

Det kan vara en användbar komponent när servern kan verifiera att kvittoidenten är pålitlig och omfattning den korrekt. Det är fortfarande viktigt att lagra det resulterande bidragsbeslutet, felmatchpolicyn och återhämtningstillståndet. Ett system kan få samma identifierare upprepade gånger, ta emot den sent eller ta emot den med en nyttolast som inte matchar den lagrade produktkontexten.

Ska en klient retry automatiskt efter en timeout?

Vanligtvis bör det fördröja statusupplösning med samma avsiktsidentitet, med begränsad backoff och tydlig användaråterkoppling. Oavsett om det ska skicka in externa inköpsbevis beror på leverantören och verifieringsdesignen. Det osäkra beteendet skapar tyst en ny inköpsförfrågan eller tillämpar ett lokalt bidrag eftersom det ursprungliga svaret var förlorat.

Hur skiljer sig förbrukningsvaror från permanenta rättigheter?

Permanenta rättigheter brukar deduplicera på konto och produkt. Konsumenter kan tillåta samma produkt att köpas många gånger, så unikhetsgränsen måste innehålla en transaktionsidentitet eller huvudbok snarare än produkt-ID ensam. Båda behöver fortfarande ett enda hållbart bidrag för varje accepterad avsikt.

Vad säger Persistium här?

Persistium är i utveckling. Denna anmärkning förklarar allmänt tillämplig integritet och testdesignmönster; det hävdar inte en offentlig inköpsprodukt, plattformscertifiering, kundincidenthistorik eller en värdtjänst. Dess kontinuitetsriktning är intresserad av samma typ av gränsade bevis och replay-säker återhämtningsdisciplin.

Relaterat systemUtforska Persistium