Stop fetching full quiz attempt review just to read the grade - #177
Merged
Conversation
VATUSAMoodle::getQuizAttempts() called Moodle's mod_quiz_get_attempt_review
web service once per attempt to read a single field (grade), but that
endpoint returns the entire rendered attempt review — every question, every
response, ~2.17 MB — per call. Driven by scheduled jobs in the api repo
(moodle:competency every 10 min, moodle:sendexamemails every 5 min) that
share this identical class, this amounted to ~33,000 calls/day and ~2
TB/month of outbound traffic from academy.vatusa.net, ~98.6% of that
droplet's total egress (see the migration cost analysis that surfaced this).
The review's grade is just quiz_rescale_grade(sumgrades, quiz) =
round(sumgrades / quiz.sumgrades * quiz.grade), and both sumgrades (per
attempt) and quiz.sumgrades/quiz.grade (per quiz) already live in the
Moodle database this class already queries via DB::connection('moodle')
for other fields. Compute the grade from there instead, batched per call
and memoized per quiz for the life of the instance — no behavior change
for any consumer, just no more multi-megabyte HTTP round-trips.
Mirrors the same fix landing in vatusa/api (VATUSAMoodle.php is duplicated
across both repos). Verified in Docker against a fixture 'moodle' database
using api's identical class: grades match the old review-derived formula
exactly for both 1:1 and scaled quizzes, fail-closed behavior on missing
data is preserved, and no calls to mod_quiz_get_attempt_review occur.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Summary
VATUSAMoodle::getQuizAttempts()(duplicated identically invatusa/api) called Moodle'smod_quiz_get_attempt_reviewweb service once per attempt to read a single field (grade) — but that endpoint returns the entire rendered attempt review (every question, every response, ~2.17 MB) per call.api(moodle:competencyevery 10 min,moodle:sendexamemailsevery 5 min) that share this class, this amounted to ~33,000 calls/day and ~2 TB/month of outbound traffic fromacademy.vatusa.net— ~98.6% of that droplet's total egress. This was surfaced while costing out an Azure migration: the bill for that traffic alone (~$193/mo on metered Azure egress) would exceed the entire nonprofit grant.gradeis justquiz_rescale_grade(sumgrades, quiz)=round(sumgrades / quiz.sumgrades * quiz.grade). Bothsumgrades(per attempt, inmdl_quiz_attempts) andquiz.sumgrades/quiz.grade(per quiz, inmdl_quiz) already live in the Moodle database this class already queries viaDB::connection('moodle')for other fields — no need to go over HTTP at all.getQuizMeta()helper (memoized per quiz id for the life of the instance) plus a single batchedwhereInquery for attemptsumgrades, replacing the per-attempt review call ingetQuizAttempts().[]on missing/unresolvable data.vatusa/api, which also fixes a second, independent call site there and has a note on a Docker dev-environment quirk found along the way: Stop fetching full quiz attempt review just to read the grade api#118Test plan
moodledatabase usingapi's identical class (this repo has no local Docker dev harness of its own —current's only compose file is the production build, per itsCLAUDE.md): grades match the old review-derived formula exactly for both 1:1 and non-trivially-scaled quizzes,getQuizMeta()memoization confirmed, fail-closed behavior preserved for a missing attempt and an unknown quiz id. The change here is identical to the verifiedapichange.php -lsyntax check passes. (current's Composer deps aren't installed in this environment, sophpunitcouldn't be run locally here —api's identical suite passed 18/18.)mod_quiz_get_attempt_reviewcall volume inacademy.vatusa.net's Apache access log drops to ~0, and outbound bandwidth drops toward the ~300 GB/month baseline of genuine site traffic.🤖 Generated with Claude Code