Remove Django server-side response cache - #605
Conversation
Add updated_at field to JsonConfig model, use ConditionalGetMixin for all visualization views, and short-circuit 304 responses in VisualizeEmbedded before expensive computation.
Add proper cache control for embedded visualizations
- Add pylint disable for too-few-public-methods (it is a mixin) - Add docstring to get() method - Rename last_modified/if_modified_since to camelCase Co-Authored-By: Claude Opus 4.6
Full HTTP response caching is handled by Cloudflare at the edge.
The Django file-based cache middleware was redundant and added
complexity (vary_on_headers hack, cache.clear() on every save).
- Remove UpdateCacheMiddleware and FetchFromCacheMiddleware
- Replace file-based CACHES with LocMemCache (still needed for rate limiting)
- Remove vary_on_headers('increment') from Visualize and VisualizeBallotpedia
- Remove cache.clear() from cloudflare.py and Movie.save()
- Remove test_cache_speed and test_cache_works (tested removed behavior)
Co-Authored-By: Claude Opus 4.6Co-Authored-By: Claude Opus 4.6
artoonie
commented
Mar 5, 2026
skaphan
commented
Mar 6, 2026
Superseded by #608 which fixes the server-side cache instead of removing it. |
skaphan
commented
Mar 16, 2026
via email
HI Armin,
Just FYI I am hoping to help RCV123 migrate to my cloud-based minimized rcvis instance so they can avoid hitting your server at all.
I have it deployed in staging in a docker container on Google Cloud already and my app in staging is using it with no problem.
To answer your question at the end, you are right -- it would only save regenerating the view if the browser already had it cached, but
I think we're beyond this now, right?, since the server cache is still in place (in the PR).
I think it will be the best of all worlds, if my understanding is correct anyway. You won't get fetches every 10 minutes when max-age times out,
and the server cache will be able to respond with 304 instead of even sending a cached page at least some of the time.
Shel … On Mar 5, 2026, at 12:14 PM, Armin Samii ***@***.***> wrote:
artoonie
left a comment
(artoonie/rcvis#605)
<#605 (comment)>
It seems there's some tension between supporting RCV123, which has frequent updates, and supporting real elections, which are usually static. The increase in PATCH() calls (and subsequent cache clearing) have already doubled RCVis' server costs, so that caching is important.
To break this down, take a look at RCVis server response times:
image.png (view on web) <https://github.com/user-attachments/assets/3e8a309b-8674-4dc9-9871-9d37bffebe72>
At just 750 requests per minute, response times starts to go up.
Cloudflare isn't a catch-all here: we need to populate the Cloudflare cache for each Point of Presence (each "exit node"). Given the global interest in US elections, that often means populating 100+ PoPs on election night with dozens of elections. Our local cache is protection against that
You mentioned "even cache misses at Cloudflare skip expensive graph computation" -- I'm not sure I see how without this. If neither the browser nor cloudflare has the page in cache, how are we skipping the expensive graph computation?
—
Reply to this email directly, view it on GitHub <#605 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AABCNY5MAL6LQMOOTJWALC34PHNZLAVCNFSM6AAAAACWHNVJ7SVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DAMBXGQ4DMMRRGM>.
You are receiving this because you authored the thread.
|
artoonie
commented
Mar 16, 2026
Hi Shel, I think a separate instance running RCVis makes a lot of sense for the RCV123 use case, and is allowed by the copyleft license (just make sure the RCV123-specific RCVis remains open-source if it deviates at all). Apologies I haven't gotten a chance to review your other PRs yet! I will try to get to them this week. |
skaphan
commented
Mar 16, 2026
via email
Hi Armin,
No worries. I should mention I will be traveling again starting Thursday and may have limited bandwidth to respond or do anything for 10 days after that. It may be possible but I'm not sure.
Given my somewhat modal nature, I hope you'll be able to get to these things before my brain switches gears and I don't look at code again for another 6 months!!! I'd like to get this all wrapped up before that happens and I while I can still remember what I'm doing.
As far as the version of rcvis we'll be running, the only mods I'm expecting are that some things have been removed to make containerization easier, and there are some changes like we talked about that you just might not want. Other than that, it's out of the box. If you want me to make that version publicly available I'm happy to oblige. I'm not quite sure how to go about that at the moment.
I just committed a minor revision of the pie chart component that fixes some css issues. I *think* I've addressed everything you wanted me to deal with.
Right now the "component factory" repo rcv-pie-chart is private and I invited you. I just need to put a license in there before opening that up.
I think you chose LGPL. I have been debating the right license for the pie chart. It's either that or MIT I think. From what I understand that's most common
for components like this. I'd be interested in your views.
One more thing I wanted to ask about. I saw the discussion between you and David Bangs regarding the handling of the threshold. I don't see where that shows up
in the visualizations. Am i looking right at it and not seeing it? How do you utilize that?
Shel … On Mar 16, 2026, at 10:35 AM, Armin Samii ***@***.***> wrote:
artoonie
left a comment
(artoonie/rcvis#605)
<#605 (comment)>
Hi Shel, I think a separate instance running RCVis makes a lot of sense for the RCV123 use case, and is allowed by the copyleft license (just make sure the RCV123-specific RCVis remains open-source if it deviates at all).
Apologies I haven't gotten a chance to review your other PRs yet! I will try to get to them this week.
—
Reply to this email directly, view it on GitHub <#605 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AABCNY7DABMHUZHSVDGNRGD4RA3OFAVCNFSM6AAAAACWHNVJ7SVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DANRZGQZTQMBYGY>.
You are receiving this because you modified the open/close state.
|
artoonie
commented
Mar 19, 2026
I fixed up a few linter issues and merge conflicts and deployed this! I'll monitor metrics over the next few days to make sure it works as expected. I think LGPL or MIT are both fine, no strong opinions on that. Re: threshold: RCVis supports simply not including a threshold. The previous "errors" were caused by putting "fake data" (zeros) for the threshold, which RCVis respected and tried its best to explain. The solution was just to not include any fake data in the JSON sent to RCVis. I will try to take another look at the pie PR ASAP -- these PRs take some effort to review in full, but I understand your time constraints to avoid a context switch. |
skaphan
commented
Mar 20, 2026
via email
Wonderful! I assume this is the cache fixing PR not the one that removed the serve side cache as the title suggests... Good to have this one behind us. Of course let me know if you run into any trouble. Glad I could help with this.ShelOn Mar 19, 2026, at 22:17, Armin Samii ***@***.***> wrote:artoonie left a comment (artoonie/rcvis#605)
I fixed up a few linter issues and merge conflicts and deployed this! I'll monitor metrics over the next few days to make sure it works as expected.
I think LGPL or MIT are both fine, no strong opinions on that.
Re: threshold: RCVis supports simply not including a threshold. The previous "errors" were caused by putting "fake data" (zeros) for the threshold, which RCVis respected and tried its best to explain. The solution was just to not include any fake data in the JSON sent to RCVis.
I will try to take another look at the pie PR ASAP -- these PRs take some effort to review in full, but I understand your time constraints to avoid a context switch.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you modified the open/close state.Message ID: ***@***.***> |

Why remove Django's server-side response cache
The Django file-based cache middleware (
UpdateCacheMiddleware/FetchFromCacheMiddleware) was the original mechanism for avoiding redundant graph computation on repeated page loads. It served that purpose, but it is now redundant and counterproductive given the current architecture:1. Cloudflare already handles edge caching
Dynamic pages are cached at Cloudflare's CDN, which handles the high-traffic case (millions of requests during bursts). The
ConditionalGetMixinreturns 304 when content has not changed, so even cache misses at Cloudflare skip expensive graph computation. The Django middleware is a second cache layer that does not add meaningful value.2. The middleware requires workarounds that add complexity
vary_on_headers('increment')-- decorates several views with aVaryheader for a fake HTTP header that no client ever sends. This is a no-op (every request has the same empty value, so it never affects caching) and can be removed as dead code.cache.clear()incloudflare.pyandMovie.save()-- every CDN purge and movie save also had to clear the local Django cache. These become dead code.DISABLE_CACHEenvironment variable -- needed for development/testing to work around the cache. Goes away entirely.3. It causes confusing behavior during development and testing
Stale cached responses make it hard to tell whether code changes are taking effect. We hit this directly while testing the friendly-embed-404 change -- the cache was serving old responses and masking the actual view behavior.
4. What we keep
ConditionalGetMixinfor 304 responses (unchanged, with linter fixes in Fix linter issues in ConditionalGetMixin #604)LocMemCachefor upload rate limiting (the only actual use ofdjango.core.cachein views.py)Summary of changes
UpdateCacheMiddlewareandFetchFromCacheMiddlewarefrom MIDDLEWAREvary_on_headers('increment')from Visualize and VisualizeBallotpedia (was a no-op)cache.clear()fromcloudflare.pyandMovie.save()test_cache_speedandtest_cache_works(tested the removed middleware behavior)cache,patch,get_data_for_view)Net effect: 5 files changed, ~120 lines removed, no new code.
Test plan