perf: cache /v1/genres/popular with 15-minute TTL#964
Merged
Conversation
The endpoint ran a GROUP BY genre scan over the tracks table plus an in-process normalize/merge/sort on every request. Cache the normalized result slice in an otter TTL cache (matching the existing relatedUsersCache / qualifiedPlaylistsCache pattern), keyed by (limit, offset, startTime bucket) where the bucket is startTime truncated to the 15m TTL. min_count is applied per request after the cache lookup so a single cached slice serves every threshold, and the cached slice is treated as immutable (the handler builds a fresh filtered slice rather than aliasing it). Adds a DB-free unit test for the cache key/bucketing contract, and clears the cache in the access-authorities test so its post-mutation re-read isn't served a stale cached count. Co-Authored-By: Claude Opus 4.8 (1M context) <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.
What
GET /v1/genres/popularran aGROUP BY genrescan over thetrackstable — plus an in-process normalize/merge/sort — on every request, with no caching. This adds a 15-minute in-memory TTL cache.How
genresPopularCache(otter.Cache[string, []PopularGenre], 15m TTL) onApiServer, built and wired inNewApiServerexactly like the existingrelatedUsersCache/qualifiedPlaylistsCache.getPopularGenres()which does the DB query + genre normalization/merge/sort, caches the result, and returns it. Keyed by(limit, offset, startTime bucket), where the bucket isstartTimetruncated to the 15m TTL (startTime is a rolling window, so bucketing keeps the key stable within a window; the DB query still uses the exactstartTimeon a miss).min_countis applied per request after the cache lookup, so one cached slice serves every threshold. The cached slice is treated as immutable — the handler builds a fresh filtered slice rather than aliasing it.NormalizeGenrevariant-merge + re-sort logic is unchanged, just moved behind the cache.Tests
TestGetPopularGenresCache— DB-free unit test pinning the cache-hit path and the(limit, offset, bucket)key contract (a miss reaches the nil pool and panics, proving the key actually differs).TestGenresPopularExcludesAccessAuthoritiesTracksnow callsgenresPopularCache.Clear()after its DB mutation so the re-read reflects the change instead of the cached count.go build ./...,go vet ./api/..., and the new unit test pass locally. DB-backed tests run in CI.🤖 Generated with Claude Code