Conversation
Cache the rendered page in the shared cache store, keyed on
"sponsors/index/v1/#{Sponsor.active.maximum(:updated_at)&.to_fs(:usec)}",
so a warm request costs one cache read instead of re-rendering 721
sponsor fragments (~1.3s CPU-bound per render). Solid Cache is
DB-backed, so the body also survives deploys and dyno restarts.
The key is computed before the records load so a save committing
between the two queries self-heals on the next request, and the v1
segment lets a reviewer invalidate the body when the view changes.
mroderick
force-pushed
the
performance/cache-sponsors-index
branch
from
September 17, 2026 09:06
cfcac00 to
7b57f49
Compare
mroderick
marked this pull request as ready for review
September 17, 2026 09:12
Collaborator
Author
|
The numbers are no longer accurate, since we merged #2896 ... but the idea is still the same. |
Warm requests no longer instantiate 721 AR objects they never use; the load only runs on a cache miss, so the warm path is one `maximum` query plus one cache read. Matches the corrected proposal in #2885.
olleolleolle
approved these changes
Sep 19, 2026
olleolleolle
enabled auto-merge
September 19, 2026 19:59
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
/sponsors re-rendered all 721 sponsor fragments on every request (~1.3s CPU-bound median, ~2.5M allocations), even when every fragment was a cache hit. The page body is now cached in the shared cache store, keyed on the latest active sponsor's updated_at. A warm request costs one
maximumquery plus one cache read; the sponsor load and render only run on a miss.Correction to the original diagnosis (#2885): the per-sponsor fragments already lived in Solid Cache and survived deploys and restarts, so a wiped store was never what caused the 17-21s cold renders. The likely mechanism is eviction or expiry in Solid Cache forcing a full rebuild. This change doesn't make those rebuilds cheaper — a miss still costs the full ~17-21s render — it makes them rare: one long-lived body entry instead of 721 fragments under constant eviction pressure.
Design decisions
sponsors/index/v1/{Sponsor.active.maximum(:updated_at)&.to_fs(:usec)}. The manually bumped v1 segment lets a reviewer invalidate the body when the view or partials change; without it, a deploy that changes the template keeps serving the cached body until the next sponsor save.render_to_string(layout: false), thenrender html:), so CSRF meta tags and navigation stay fresh.updated_at(update_columns,update_all) leave the key unchanged and the page stale. No in-app caller does this today; a request spec documents the accepted gap.Test plan
spec/requests/sponsors_spec.rb) covers rendering, the cache hit (body unchanged when no sponsor's updated_at changed) and the re-render after a sponsor save.Post-Deploy Monitoring & Validation
/sponsorsendpoint's mean and 95th-percentile view runtime should drop from ~1.3s median to tens of milliseconds once the key is warm. Warm requests issue 1 query./sponsorsview_runtime should stay low. An eviction or expiry of the body entry still costs a full build on the next request; expect that only after a sponsor edit./sponsorsserving stale content for more than a few minutes after a sponsor edit would mean the key is not changing; investigateSponsor.active.maximum(:updated_at)and Solid Cache health. Rollback is a revert; the previous uncached behaviour is restored.Fixes #2885
Related: #2803, #2883