A Game Wallet Is More Than a Number: Handling Retries and Concurrency
A game wallet often starts as a single balance field. That is fine for a prototype, but payment retries and unreliable networks quickly make the number hard to trust. A player can tap “buy,” lose the connection, and try again. A store callback can arrive more than once. Two devices can spend the same account at nearly the same time. The fix is to treat the balance as a cached view of a ledger.…
A game wallet begins as a simple balance field, but handling payment retries and network instability turns that number into a complex challenge. When a player attempts to purchase but loses connection, the store callback may arrive multiple times. Even two devices might attempt to spend the same account simultaneously. The solution is to treat the balance as a cached view of a ledger, recording every change rather than silently updating the balance.
Events such as verified payments, item purchases, refunds, and administrative adjustments should be logged. The current balance is still useful for quick reads, but the ledger provides context for its origin.
To ensure payment delivery is idempotent, create an idempotency key from the provider and transaction ID, then enforce uniqueness in the database. The delivery process involves verifying the external transaction, recording the payment, granting currency with the unique key, marking the delivery complete, and returning the original result for future retries. This approach prevents temporary network issues from leading to double grants.
While client-side balance checks provide interface feedback, they cannot protect an account. The server must lock the wallet row, verify the available amount, write the ledger entry, and update the cached balance within one transaction. The same request key should yield the original purchase result rather than recharging twice. Keep payment, wallet, and item orders separate to distinguish real-money payments, virtual-currency movements, and item deliveries.
This separation simplifies refunds and reconciliation. Identifying which step is missing when something goes wrong becomes easier, as each step can be traced individually.
Before developing a large shop user interface, test repeated callbacks, crashes occurring between payment and delivery, concurrent spends, timeout retries, failed item deliveries, and refunds after currency has been spent. The crucial insight is that a wallet is not merely a number; it is a record of decisions. By making those decisions explicit and idempotent, payment failures become understandable.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.