Scaling a Bonus Engine: How We Improved Performance, Reliability, and Database Efficiency
Introduction
While integrating a bonus engine into a high-traffic gaming platform, we encountered several performance and reliability challenges. The bonus engine was responsible for player registration, bonus eligibility checks, and reward processing, making it a critical component of the platform.
As traffic increased, we noticed slow database queries, duplicate requests caused by retries, and unnecessary load on downstream services. This article explains the challenges we faced, how we identified the root causes, and the optimizations that significantly improved the system.
Challenge 1: Excessive Retry Requests
One of the biggest challenges was handling retries between multiple services. When a request failed because of a timeout or temporary network issue, upstream systems automatically retried it. In some cases, multiple system layers performed retries independently.
This resulted in:
- Duplicate requests reaching the bonus engine
- Increased database load
- Higher response times
- Duplicate processing attempts
Solution
We redesigned the retry strategy by clearly defining where retries should occur. Instead of allowing every service to retry independently, retry handling was centralized and controlled.
Key improvements included:
- Limiting the number of retry attempts
- Avoiding duplicate processing
- Handling transient failures gracefully
- Improving overall system stability
This reduced unnecessary traffic while maintaining reliability.
Challenge 2: Slow Database Queries
During performance analysis, we identified several queries that consistently took more than 30 seconds to execute. These long-running queries directly affected the response time of the bonus engine.
Root Cause
The queries were scanning large tables without taking advantage of efficient indexing. As the amount of player and transaction data increased, query performance degraded significantly.
Database Optimizations
We performed a detailed analysis of the execution plans and optimized the database schema.
Composite Indexes
We created composite indexes on columns that were frequently used together in filtering conditions. Instead of scanning the entire table, the database was able to locate matching records much faster.
Unique Indexes
Where appropriate, unique indexes were introduced to:
- Prevent duplicate records
- Improve lookup performance
- Enforce data integrity
Query Optimization
Several SQL queries were rewritten to improve execution efficiency.
- Reducing unnecessary joins
- Selecting only required columns
- Eliminating redundant conditions
- Improving filter ordering
- Leveraging existing indexes effectively
After optimization, query execution time dropped dramatically, resulting in much faster API responses.
Challenge 3: Bonus Engine Player Registration
Player registration was one of the most frequently executed operations. Every new player triggered multiple validation and bonus-related checks before registration could be completed. As traffic increased, this endpoint became a performance bottleneck.
Improvements
We optimized the registration flow by:
- Reducing unnecessary database calls
- Optimizing validation queries
- Improving transaction handling
- Using indexed lookups for player verification
These changes reduced response time and improved scalability under heavy load.
Challenge 4: Transaction Logging
The bonus engine processes financial and promotional transactions, making accurate logging essential. Initially, troubleshooting production issues required searching through logs from multiple services.
Solution
We improved transaction logging by recording important information such as:
- Request identifiers
- Player identifiers
- Transaction status
- Processing time
- Error details
With structured logging, it became much easier to trace a request across different services and quickly identify failures.
Challenge 5: Redesigning the Database with Composite Keys
While analyzing slow queries, we discovered that several tables were using only a single-column primary key, even though most queries filtered on multiple columns together.
Bonus-related operations frequently searched records using combinations such as:
- player_id + bonus_id
- player_id + campaign_id
- player_id + transaction_id
Although individual indexes existed on these columns, PostgreSQL still had to perform additional work to combine results or scan a large number of rows.
Root Cause
The database design did not fully reflect how the application accessed the data. Since most queries filtered on multiple columns simultaneously, relying on single-column indexes led to inefficient execution plans and higher query execution times.
Solution
We redesigned the schema by introducing composite keys and composite indexes for frequently accessed column combinations.
A composite primary key can enforce uniqueness across a player and bonus:
PRIMARY KEY (player_id, bonus_id)A dedicated composite index can optimize the same access pattern:
CREATE INDEX idx_player_bonus
ON bonus_transactions(player_id, bonus_id);Instead of searching by one column and filtering on another afterward, PostgreSQL could directly locate the required rows using the composite index.
Benefits
Introducing composite keys provided several improvements:
- Faster lookups for multi-column searches
- Reduced full table scans
- Lower database I/O
- Improved query execution plans
- Better enforcement of business rules by preventing duplicate player-bonus records
Using (player_id, bonus_id) as a composite key ensured that the same player could not be assigned the same bonus multiple times, maintaining data integrity at the database level.
Results
After redesigning the schema and updating the queries to take advantage of the new indexes, query execution times dropped significantly. Operations that previously required scanning large datasets were able to retrieve records efficiently through indexed lookups.
This optimization improved response times and reduced CPU utilization and overall database load during peak traffic, allowing the bonus engine to handle a much higher volume of concurrent requests.
Overall Results
After implementing these optimizations, we observed significant improvements:
- Reduced duplicate processing caused by uncontrolled retries
- Faster database query execution
- Lower database resource utilization
- Improved player registration performance
- Better transaction traceability through structured logs
- Increased reliability during peak traffic
Lessons Learned
Building a scalable backend involves much more than writing business logic. As traffic grows, retry strategies, efficient database design, indexing, query optimization, and observability become just as important as the application code itself.
By carefully analyzing bottlenecks and optimizing both the application and database layers, we significantly improved the performance and reliability of the bonus engine while creating a more maintainable architecture for future growth.