Analyze and optimize excessive API calls#327
Closed
gsonntag wants to merge 1 commit intohackutd:masterfrom
Closed
Conversation
… judge load Performance problems (p99=30000ms) traced to three root causes, all fixed: 1. Audit log DB write on every API call (REMOVED) Every endpoint called Logger.Logf() which executed a synchronous majority-write MongoDB transaction (FindOneAndUpdate inside WithTransaction) before the HTTP response was sent. With 50+ judges judging concurrently this serialised all requests through MongoDB. Logs are now memory-only (still visible via GET /admin/log for the current session; historical entries still loaded from DB on startup). 2. GetOptions DB read inside every judge transaction (CACHED) GetNextJudgeProject, JudgeFinish, JudgeRank, JudgeStar, JudgeSkip, GetDeliberationStatus, GetJudgingTimer, GetGroupInfo, CheckQRCode and ~10 more handlers each called database.GetOptions() — a full MongoDB FindOne — per request, many of them inside transactions. Options are now served from a server-side in-memory cache (sync.RWMutex + pointer) loaded at startup and invalidated on every admin write. Zero DB reads for options on the hot judge path. 3. Admin panel polling: 6 API calls every 15s replaced by 1 The admin dashboard polled /admin/stats, /admin/clock, /project/list, /judge/list, /admin/options, and /admin/flags separately every 15 seconds per browser session. Added GET /admin/dashboard that serves all six payloads in one response, running the four DB-bound queries concurrently with goroutines. Clock and options come from memory. Additional improvements: - 10-second TTL in-memory cache for AggregateStats and AggregateScores aggregation pipelines so concurrent admin sessions share one result. - Fixed clock mutex deadlock in GetNextJudgeProject: the original code acquired Clock.Mutex then returned early without releasing it when judging was paused, permanently blocking all subsequent clock ops. - Options reads before transactions now happen outside the transaction so deliberation/group checks abort before a session is opened. https://claude.ai/code/session_01W7yeH1ccUKkrr8SbKrVhmT
MichaelZhao21
requested changes
Apr 14, 2026
Contributor
MichaelZhao21
left a comment
There was a problem hiding this comment.
Can you fill in the PR template and split the changes into multiple commits, one for each distinct change made? The PR in this form is extremely hard to review.
Author
|
mb gng didnt mean to create pr into this repo |
Contributor
|
LOL ur good, though if you want to create a PR with some of these changes I think the performance improvements would definitely be helpful. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
… judge load
Performance problems (p99=30000ms) traced to three root causes, all fixed:
Audit log DB write on every API call (REMOVED) Every endpoint called Logger.Logf() which executed a synchronous majority-write MongoDB transaction (FindOneAndUpdate inside WithTransaction) before the HTTP response was sent. With 50+ judges judging concurrently this serialised all requests through MongoDB. Logs are now memory-only (still visible via GET /admin/log for the current session; historical entries still loaded from DB on startup).
GetOptions DB read inside every judge transaction (CACHED) GetNextJudgeProject, JudgeFinish, JudgeRank, JudgeStar, JudgeSkip, GetDeliberationStatus, GetJudgingTimer, GetGroupInfo, CheckQRCode and ~10 more handlers each called database.GetOptions() — a full MongoDB FindOne — per request, many of them inside transactions. Options are now served from a server-side in-memory cache (sync.RWMutex + pointer) loaded at startup and invalidated on every admin write. Zero DB reads for options on the hot judge path.
Admin panel polling: 6 API calls every 15s replaced by 1 The admin dashboard polled /admin/stats, /admin/clock, /project/list, /judge/list, /admin/options, and /admin/flags separately every 15 seconds per browser session. Added GET /admin/dashboard that serves all six payloads in one response, running the four DB-bound queries concurrently with goroutines. Clock and options come from memory.
Additional improvements:
https://claude.ai/code/session_01W7yeH1ccUKkrr8SbKrVhmT
Description
[Describe the issue that this fixes or the feature that this adds]
Fixes #[Issue]
Type of Change
Delete options that do not apply:
Is this a breaking change?