Why the gifting system in a mobile game breaks during peaks
A peak does not occur at launch, but when a mobile game's gifting system receives an avalanche of simultaneous sends: an event, a large broadcast, the opening of a season.
The client sends a request, the server fails to confirm the operation in time, the client retries — and instead of one gift, two are credited.
Typical failure points are a resend without an operation key (duplicate credits), a debit from the sender without a credit to the recipient (a lost gift that the player already sees in their history), and a stuck operation: it cannot be rolled back automatically, nor can it be completed.
A separate source of duplicates is purchase confirmation in Google Play: the payment has gone through, but the server requests verification again and credits the gift a second time.
None of these failures is visible on availability charts — it is not the service that goes down, but the correctness of gift accounting.
The cost is measured in support hours: every discrepancy means manual investigation, a request for screenshots, compensation, and a database balance adjustment.
While such cases are isolated, they are handled manually; during a peak, the count runs into hundreds of tickets, and the investigation queue grows faster than the team can clear it.
The root causes are usually the same: limits are checked on the client rather than the server, retries happen without deduplication, the balance is written synchronously with the grant, and there is no reconciliation of credited and debited amounts at all.
Below we break down how this is closed — from idempotent grants to queues and push notifications that do not add load during a peak.
The effect of managed grants: what changes in the numbers
The share of successful sends stops depending on the player's connection quality. At every step of the grant there is confirmation and a retry with the same operation key: the gift is either delivered or will be delivered; there is no third state. Send conversion grows without changes to the game rules themselves.
Recovery time after a failure is measured in minutes rather than a wave of tickets. The gift queue survives a process restart, limits are lifted automatically, and degradation occurs across individual channels — the grant may slow down, but it does not switch off entirely. The engineer sees which step is lagging and restores it selectively.
The volume of manual support tickets falls because the player sees the gift status, not “something went wrong.” Typical situations — did not arrive, arrived twice, daily limit reached — are closed automatically, and only genuine disputed cases remain for a human.
Duplicate credits disappear as a class of failure: a repeat delivery does not create a second gift, and balance reconciliation catches a discrepancy before the player notices it. Previously this was investigated manually from logs; now there are simply no discrepancies.
We measure all four metrics — successful sends, recovery time, manual tickets, and duplicates — before and after the changes using the same methodology. This makes it clear what each step delivered: where send conversion increased and where time to return to normal decreased.
Grant options: bundle, direct transfer, exchange
The grant mode determines how an item leaves the item catalog and ends up in the recipient's inventory. Daily limits, recording in the operation history, and how easy it is to roll back an erroneous or duplicate grant depend on it.
Once launched, this is almost impossible to redo: already granted items will have to be migrated, and the economy balance recalculated from scratch.
The modes below are not mutually exclusive — a gift bundle often coexists with direct transfer between players, while gift exchange lives in a separate loop.
The choice should be made for the event's goal and for who initiates the grant: the system by rule, one player, or two by mutual agreement.
| Grant mode | When it fits | Limitations |
|---|---|---|
| Gift bundle | Holiday events, compensations, starter bonuses: the composition is strictly defined by the catalog | No targeting — the bundle goes to everyone by rule, and personal recipient selection is unavailable |
| Direct transfer between players | In-game currency, consumables, gifts to friends from the list | Daily limits are mandatory, otherwise resources are siphoned between accounts in the same group |
| Gift exchange | When items should return to circulation rather than settle in recipients' inventories | A two-sided deal: rollback is more complex, requiring a journal on both sides and checks for reciprocal transfers |
The grant mode is locked in before the first item is granted: limit rules, the operation journal, and rollback logic are described in one place and are not duplicated on the client. Then adding a new mode is an extension of the rules, not a rework of the economy.
Implementation stages: from audit to handover to support
The stages are arranged so that each next step builds on a verified previous one: until the current accounting is described, it is too early to design the schema, and limits cannot be configured until retries are closed. Below is the path from day one to the point when the system runs without us.
- Accounting audit. We look at where the sender's balance is stored, how delivery is recorded, and what happens when the connection between the game server and the payment loop breaks. The output is a map of bottlenecks and a list of failures that already occur.
- Data schema. We design gift, status, and operation journal tables with indexes for real queries: “what the player has already received,” “how much they sent in a day.” No query reads the entire history.
- Retry protection. Each send is assigned a unique operation key — a repeat request returns the result of the first rather than creating a second gift. Debit and credit happen in a single transaction.
- Limits. We set boundaries per sender, recipient, and the pair between them with daily and weekly windows. We separately describe behavior on exceeding them: rejection, queueing, or deferral.
- Load testing. We run peak scenarios — holiday events and mass broadcasts. We check whether the limits hold, whether response time grows, and whether the journal remains complete.
- Support training. We hand over procedures for typical tickets: the gift did not arrive, arrived twice, the limit triggered early. We show how to reconstruct the gift's path from the journal without manually editing the balance.
- Handover. We close out access, set up anomaly alerts, and agree on incident response. After that, rules and limits are changed through the standard process, without taking the system apart again.
What we hand over: configurations, schemas, procedures
In the app, the player sees a storefront, while the gift itself lives in the rules, limits, and accounting records on the server side.
Therefore, at acceptance we hand over not only builds, but also the descriptions your team uses to change event conditions, investigate disputed credits, and answer players without us.
- Credit rules — a table “event → what and how much is credited → what is debited” with specified exceptions: gift cancellation, return, repeat delivery, undelivered push notification.
- Accounting schema — the path of each gift from sender to recipient: statuses, operation idempotency key, change journal, and source (game, promo, support).
- Limit table — daily and weekly ceilings per player, pair, level, and gift type, behavior at the boundary, and the procedure for manual increases.
- Integration documentation — contracts of game services and the admin panel: which events arrive, which response is considered successful, what to do when there is no response.
- Support procedures — step-by-step scenarios: find an operation by ID, distinguish a credit from a duplicate, roll back an erroneous gift, formulate a reply to the player.
- Disputed operation investigation procedures — escalation levels, response times, evidence package (balance snapshot, status journal), and compensation procedure.
- Operations instructions — gift delivery metrics, alert thresholds, enabling the kill switch on credits, and shift handover.
The check is simple: an engineer who did not participate in the development reproduces a credit and closes a ticket using these documents. Anything that fails this check is brought up to handover standard.
Case study: more sends without more server load
Before the rework, a gift went into the queue asynchronously, and the send result was not recorded anywhere as a separate state.
During peak hours — mass events, evening windows — the share of failed sends reached several percent, and the user either saw “gift not sent” or, worse, sent again.
Support received hundreds of tickets per month, and each was investigated manually: using app logs and database records, it was necessary to determine whether the item was debited and whether it reached the recipient. Investigating one disputed operation took more than half an hour.
The key change was the operation state model. Each send generates a key, so a repeat request does not create a second record but only returns the current status: created, reserved, delivered, returned.
Debit and credit happen in a single transaction on both sides, so “the gift went out but the item was not debited” ceased to be a possible class of failure.
We separately added limits per sender and recipient and a queue with increasing delay between retries — the server stopped receiving a barrage of identical requests at peak.
What the metrics showed
| Metric | Before | After |
|---|---|---|
| Share of failed sends | several percent during peak hours | fractions of a percent, with the remainder automatically returned |
| Support tickets about gifts | hundreds per month | several times fewer, disputed cases closed without an operator |
| Investigation of a disputed operation | more than 30 minutes manually | 1-2 minutes using the operation journal |
| Peak load | degradation at a threefold increase | fourfold increase without adding nodes |
Stability during peaks is ensured not by spare hardware, but by the fact that the queue is processed in batches and priority is given to operations with an already reserved item.
Metrics were collected in Grafana using panels for error rate, queue depth, and response time — the same set of dashboards was handed over to the client's team so deviations are caught before user tickets.
For the player, the difference comes down to one thing: the gift either arrives or the item stays with them. For the team, it comes down to predictable incident investigation instead of manual reconciliations on major event days.
How is a gift different from in-game currency?
In-game currency and a gift are structured differently in accounting. Currency is a number on a balance: the server changes it with one operation, and the history remains in the journal for reconciliation.
A gift is not a number but the fact of transferring a specific item to a specific player, so gift accounting is built as a record with a unique identifier, sender, recipient, and grant time.
This leads to different reversibility. An erroneous currency credit is closed with a compensating entry: the balance returns to its previous value, and the journal record remains. A gift cannot be rolled back that way after a grant — the item is already with the recipient.
App Store payment rules require restoring purchased currency on failure, but a gift is not subject to restoration: it was either granted or not. Therefore, the return rule is set in advance — before a grant, the gift is returned to the sender; after a grant, it is not.
Limit rules also solve different problems. For currency, they restrict emission and the rate of credit to an account — this curbs inflation and fraudulent credits.
For gifts, limits are calculated by sender-recipient pairs, frequency, and item value; otherwise value is circulated between linked accounts.
The item economy depends on this directly. Crediting currency increases the total supply and devalues savings, while a gift only redistributes the existing circulation — but with unlimited transfer, items concentrate among resellers. Therefore, for gifts, a value ceiling and a ban on secondary transfer are set.
Technical concerns: limits, delays, anti-abuse protection
Concerns about gifts are usually the same: duplicates on resend, delays on a poor connection, daily limits, fresh accounts, and notifications. Below is how these areas are closed in the architecture.
Player tapped “send” twice — will the gift go out twice?
No. Each send receives a unique operation key, and the server discards a retry with the same key. The balance debit happens once, even if the requests arrived simultaneously from two devices.
Will the gift be lost if the connection drops?
No: the gift is recorded on the server before responding to the client, and the credit goes through a retry queue. The player sees the “processing” status, and after the connection is restored the operation is completed.
How are daily send limits calculated?
The server maintains counters using a sliding window rather than calendar days: separately for the number of gifts to one recipient, the total volume per day, and new accounts. When the limit is reached, the player sees the reason and the time until reset.
How is abuse from new accounts prevented?
Fresh accounts operate in a restricted mode until they build up history: gifts are available after linking, and exchange chains between linked accounts go to manual review using the event journal.
What about notifications and disputed operations?
The notification is sent after the credit is confirmed, not at the moment of sending, so there are no false pushes.
If the gift is not delivered, a timeout-based return is triggered, and the dispute is investigated using the journal: the initiator, operation key, and all retries are visible.
Let's discuss your task: what to send and what you will get in response
Discussing a gifting system task should not stretch into weeks of back-and-forth: it is enough to send a set of project inputs — from them we immediately see bottlenecks and do not ask about the obvious.
The more specific the data, the more accurate the stage estimate and the fewer assumptions in the work plan.
- How a gift is structured in the current model: an inventory record, a separate entity with a lifetime, or a catalog reference, and what is considered “delivered.”
- Where limits are calculated — on the client, on the game server, or in a separate gift service — and what happens when trying to exceed a daily or total limit.
- Credit and debit schema: atomicity of paired operations, idempotency of retry requests, behavior when the connection drops mid-exchange.
- How gift notifications are structured: who initiates the send, whether there is grouping during an event fan-out, and what a player sees after returning to the game a day later.
- Current metrics: share of delivered gifts, retries, support tickets worded as “gift did not arrive.”
- Platform and store rules restrictions on in-game purchases, dependency on the payment provider and its limits.
- Who on the client side makes decisions about the game balance and maintains test accounts for scenario testing.
In response, you will receive a solution design with service boundaries, a stage-by-stage work plan, a rollout procedure, and a list of risks with how each one is closed.







