Per user feed cached#22
Merged
Merged
Conversation
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.
Cache per-user gameboard feeds (countries + world domination) per team
Summary
The two remaining uncached gameboard feeds —
JSONCountriesHandlerandJSONWorldDominationHandler— are per-user (theirsolved_by_current/ current-team metrics depend on the viewer's team), so they couldn't share a per-UUID cache entry like the global feeds. This caches them per(uuid, teamID), so the heavy per-poll DB work is skipped on a cache hit while teammates correctly share a result and different teams never see each other's view.Why
JSONCountriesHandlerruns countries + active challenges + categories + all teams + all team scores + assembly;JSONWorldDominationHandlerruns active challenges + current team + all scores + win/loss computation. Each polled every 15s per client.solved_by_current(countries) and current-team metrics (domination) depend on the team — everything else is per-UUID — but caching the whole response per team is simpler and bounded (short TTL).JSONGameClockHandlerdeliberately uncached (time-based).What changes
cmd/map/handlers/json.go: both handlers resolve the current user's team up front (oneUsers.Get, hoisted from inside the handler — not an added query) and cache the response undermapctf:feed:countries:<uuid>:<teamID>/mapctf:feed:domination:<uuid>:<teamID>.serveCachedJSONbuildclosure, so a cache hit runs zero of those queries.teamID) share one cache entry; users with no team key under:0; different teams get separate entries → no cross-team leakage.respcache.go; only200responses are cached; Redis-down degrades to uncached reads.cmd/map/handlers/json_test.go:TestJSONWorldDominationFeedCacheKeysPerTeam— proves per-team separation (Alice's team's "1 completed" does not leak into Bob's "0") and that a bypassing DB write is not reflected while the L1 entry is fresh.Intentional: TTL-only (no explicit invalidation)
Per-team keys can't be invalidated with a single
DEL(would need a prefix scan over all team keys), so these two feeds rely on the 4s TTL for staleness. A capture reflects on the map/domination panel within ~4s — acceptable given the 15s poll cadence. The per-UUID global feeds (teams/activity/chat) keep their explicitinvalidateFeedcalls on score/hint/chat-post for instant updates.Behavior preserved
validatedJSONUUIDand the manager nil-checks still run before the cache lookup so invalid UUIDs / uninitialized managers never get a cached response.Performance
Users.Get(indexed) + cache hit, per ~4s per(uuid, teamID), shared across teammates and across instances via Redis.Users.Getis the key-derivation cost; it's an indexed lookup and far cheaper than the feed's queries it replaces on a hit.Risks / edge cases
Testing
TestJSONWorldDominationFeedCacheKeysPerTeam(L1-only, network-free).go vet,gofmt,golangci-lint(errorlint/gocritic/misspell) all clean.Rollout
Rebuild/restart the service. No schema or config change — the per-user feed cache activates automatically when Redis is configured (as it already is for sessions).