fix: invalidate leaderboard cache after visibility settings change#1782
Merged
Priyanshu-byte-coder merged 1 commit intoMay 31, 2026
Conversation
Root cause
----------
The leaderboard is stored at two cache layers:
1. A module-level in-process variable (_memoryCache) with a 1-hour TTL
2. A shared Redis/Upstash entry (LEADERBOARD_CACHE_KEY) with a 6-hour TTL
PATCH /api/user/settings persisted is_public and leaderboard_opt_in
changes to the database but did not invalidate either cache layer.
A user who opted out of the leaderboard remained visible for up to
one hour; a user who opted in was invisible for the same period.
Fix
---
src/lib/metrics-cache.ts
- Add cacheDelete(key): removes a single key from both the in-process
memory Map and Redis/Upstash. Used instead of invalidateUserMetricsCache
because the leaderboard is keyed by a single shared constant rather
than a per-user prefix.
src/lib/leaderboard.ts
- Import cacheDelete.
- Export clearLeaderboardCache(): sets _memoryCache = null and calls
cacheDelete(LEADERBOARD_CACHE_KEY). This evicts all cache layers so
the next leaderboard request must rebuild from the database, reflecting
the updated preferences immediately.
src/app/api/user/settings/route.ts
- Import clearLeaderboardCache from leaderboard.ts.
- After a successful PATCH, check whether updates contains is_public or
leaderboard_opt_in. If so, call clearLeaderboardCache().
- The call is wrapped in try/catch: a Redis failure must not prevent
the settings response from reaching the client.
test/leaderboard-cache-invalidation.test.ts — 11 new tests:
Cache IS cleared when:
- is_public → false (regression for Priyanshu-byte-coder#1779)
- is_public → true
- leaderboard_opt_in → false (regression for Priyanshu-byte-coder#1779)
- leaderboard_opt_in → true
- Both fields change simultaneously (cleared exactly once)
Cache is NOT cleared when:
- Only bio changes
- Only timezone changes
- Only weekly_digest_opt_in changes
Error resilience:
- clearLeaderboardCache throws → PATCH still returns 200
- Unauthenticated request → 401, no cache cleared
- Unresolved user → 404, no cache cleared
Closes Priyanshu-byte-coder#1779
|
@Ridanshi is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel. A member of the Team first needs to authorize it. |
GSSoC Label Checklist 🏷️@Priyanshu-byte-coder — please apply the appropriate labels before merging: Difficulty (pick one):
Quality (optional):
Validation (required to score):
|
d83cb7d
into
Priyanshu-byte-coder:main
4 of 5 checks passed
|
🎉 Merged! Thanks for contributing to DevTrack. If the project has been useful to you, a ⭐ star on the repo is the easiest way to support it — it helps DevTrack get discovered by more developers. Keep an eye on open issues for your next contribution! |
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.
Closes #1779
Problem
The leaderboard is cached at two levels:
_memoryCache)leaderboard:v1PATCH /api/user/settingspersistsis_publicandleaderboard_opt_inchanges to the database but does not invalidate either cache layer. A user who opts out of the leaderboard therefore remains visible to other users for up to one hour; a user who opts in remains invisible for the same duration.Reproduction: change either setting in the dashboard and immediately visit the leaderboard — the old state persists until cache expiry.
Fix
src/lib/metrics-cache.ts— newcacheDeleteRemoves a single key from both the in-process memory Map and Redis/Upstash. Complements the existing
invalidateUserMetricsCache(which scans a per-user prefix) for the case where one shared key must be evicted.src/lib/leaderboard.ts— newclearLeaderboardCacheEvicts every cache layer so the next leaderboard request must rebuild from the database, reflecting updated preferences immediately.
src/app/api/user/settings/route.ts— call invalidation after relevant PATCHesThe check runs only after a successful DB write. It is scoped to the two fields that control leaderboard eligibility; unrelated changes (bio, timezone, etc.) do not trigger a cache bust.
Cache invalidation flow
Tests —
test/leaderboard-cache-invalidation.test.ts(11 new tests)is_publicleaderboard_opt_inbio,timezone,weekly_digest_opt_in— cache NOT clearedclearLeaderboardCachethrows → PATCH still returns 200All 11 pass. The one pre-existing failure in
test/dateUtils.test.tsis a timezone boundary issue unrelated to this change.