-
Notifications
You must be signed in to change notification settings - Fork 0
Use ZCOUNT for ranks computing
#109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
* Remove the `ranks::lock_within` function. * Remove the `RecordsError::RankCompute(_)` error variant. * Remove the send of the message about the internal error about the rank compute, for the game API middleware and the GraphQL API endpoint handler. * Remove the whole documentation of the `ranks` module, since we don't use the lock mechanism anymore. * Replace the calculation of the rank by a `ZCOUNT` to count the members that have a strictly less time than the one provided. * Keep the old behavior of keeping track of the old score of the player if better, since it's relevant in case of a race-condition between an operation that could update the player's time in Redis, and another one that could retrieve the old time right after it. Make this in a Redis transaction. * Remove the whole leaderboard update mechanism when the player doesn't have the time in Redis, because it's overkill. * Remove the argument for the SQL database connection in the `ranks::get_rank` function, since we don't need it anymore. Closes: #106.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR refactors the rank computation system to use Redis's ZCOUNT command instead of ZRANGEBYSCORE + ZRANK, significantly simplifying the implementation by removing the complex locking mechanism and error handling infrastructure that was previously needed.
Key Changes:
- Replaced multi-step rank calculation with atomic pipeline using
ZCOUNTto count records below a given time - Removed the lock system (
lock_withinfunction) that prevented concurrent leaderboard operations - Removed
RankComputeErrorand all associated error handling infrastructure - Simplified
get_rankto no longer require database connection or perform leaderboard synchronization internally - Removed
update_rankfunction in favor of directzaddcalls
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
crates/records_lib/src/ranks.rs |
Major refactor: removed locking system, simplified get_rank to use ZCOUNT in atomic pipeline, removed 200+ lines of complex synchronization code |
crates/records_lib/src/error.rs |
Removed RankComputeError variant from error enum |
crates/records_lib/src/mappack.rs |
Updated get_rank call to remove conn parameter |
crates/records_lib/src/leaderboard.rs |
Updated get_rank call to remove conn parameter |
crates/graphql-api/src/objects/root.rs |
Updated get_rank calls to remove conn parameter |
crates/graphql-api/src/objects/player.rs |
Updated get_rank calls to remove conn parameter |
crates/graphql-api/src/objects/map.rs |
Updated get_rank calls to remove conn parameter |
crates/game_api/src/main.rs |
Removed mask_rank_compute_error middleware |
crates/game_api/src/http/player_finished.rs |
Updated get_rank calls and replaced update_rank with direct zadd |
crates/game_api/src/http/overview.rs |
Updated get_rank call to remove conn parameter |
crates/game_api/src/graphql.rs |
Removed RankComputeError handling logic |
crates/game_api/src/error.rs |
Removed RankComputeError error code, left comment placeholder |
crates/game_api/src/configure.rs |
Removed mask_rank_compute_error middleware and send_compute_err_msg_detached function (~165 lines) |
Comments suppressed due to low confidence (6)
crates/graphql-api/src/objects/root.rs:67
- The get_rank call here retrieves the rank without first ensuring the leaderboard is synchronized with the database. The previous implementation of get_rank would internally handle out-of-sync leaderboards, but the new implementation assumes the Redis leaderboard is already current. This can result in incorrect ranks being returned. Add a call to update_leaderboard before calling get_rank, similar to how it's done in the map queries (see map.rs lines 69 and 235).
rank: get_rank(
redis_conn,
record.map_id,
record.record_player_id,
record.time,
event,
)
.await?,
crates/graphql-api/src/objects/root.rs:306
- Each get_rank call in this loop retrieves ranks without ensuring leaderboards are synchronized. Since records can be from different maps, you'll need to either call update_leaderboard for each unique map_id before the loop, or call it inside the loop for each record's map. The previous implementation of get_rank handled synchronization internally, but the new implementation does not. This can result in incorrect ranks being returned.
let rank = get_rank(
redis_conn,
record.map_id,
record.record_player_id,
record.time,
event,
)
.await?;
crates/graphql-api/src/objects/player.rs:190
- Each get_rank call in this loop retrieves ranks without ensuring leaderboards are synchronized. Since a player's records can span multiple maps, you'll need to call update_leaderboard for each unique map_id. The previous implementation of get_rank handled synchronization internally, but the new implementation does not. This can result in incorrect ranks being returned.
let rank = get_rank(
redis_conn,
record.map_id,
record.record_player_id,
record.time,
event,
)
.await?;
crates/graphql-api/src/objects/player.rs:343
- Each get_rank call in this loop retrieves ranks without ensuring leaderboards are synchronized. Since a player's records can span multiple maps, you'll need to call update_leaderboard for each unique map_id. The previous implementation of get_rank handled synchronization internally, but the new implementation does not. This can result in incorrect ranks being returned.
let rank = get_rank(
redis_conn,
record.map_id,
record.record_player_id,
record.time,
event,
)
.await?;
crates/records_lib/src/mappack.rs:430
- Each get_rank call in this loop retrieves ranks without ensuring the leaderboard for that map is synchronized with the database. The previous implementation of get_rank would handle synchronization internally, but the new implementation does not. Consider calling update_leaderboard for each map before processing its records. This can result in incorrect ranks being returned.
rank: get_rank(
redis_conn,
map.id,
record.record.record_player_id,
record.record.time,
event,
)
.await?,
crates/graphql-api/src/objects/root.rs:103
- Each get_rank call in this loop retrieves ranks without ensuring leaderboards are synchronized. Since records can be from different maps, you'll need to either call update_leaderboard for each unique map_id before the loop, or call it inside the loop for each record's map. The previous implementation of get_rank handled synchronization internally, but the new implementation does not. This can result in incorrect ranks being returned.
let rank = get_rank(
redis_conn,
record.map_id,
record.record_player_id,
record.time,
event,
)
.await?;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Closes #106.