Skip to content

feat(gamification): cache leaderboard results and clamp max limit - #1191

Merged
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
RUKAYAT-CODER:feat/cache-leaderboard-results
Aug 7, 2026
Merged

feat(gamification): cache leaderboard results and clamp max limit#1191
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
RUKAYAT-CODER:feat/cache-leaderboard-results

Conversation

@RUKAYAT-CODER

Copy link
Copy Markdown
Contributor

Summary

Implements #1159 — caches the top-N leaderboard in Redis with a short TTL and clamps the caller-supplied limit to a documented maximum, so repeated reads skip the expensive ORDER BY ... DESC sort and a caller can never force an unbounded full-table sort / oversized response.

Changes

  • src/gamification/leaderboards/leaderboards.service.ts
    • Limit clamp: getTopPlayers() and getBadgeLeaderboard() now coerce limit into the safe range [1, MAX_LEADERBOARD_LIMIT] (MAX_LEADERBOARD_LIMIT = 100, matching the cap already used by the paginated getLeaderboard) instead of passing it straight into take()/limit(). Non-finite values fall back to the documented maximum.
    • Redis caching: both top-N methods use a cache-aside pattern over the shared REDIS_CLIENT connection with a 60-second TTL (LEADERBOARD_CACHE_TTL_SECONDS). Cache keys are scoped by leaderboard type, badge category, and clamped limit. A Redis read/write failure fails open to the database, so leaderboard reads never break.
    • The Redis client is injected @Optional(), so the service keeps working when Redis is not wired up.

Tests

  • Added src/gamification/leaderboards/leaderboards.service.spec.ts (13 cases) covering:
    • max-limit clamp for both the points and badge leaderboards (and non-positive coercion)
    • cache hit/miss behaviour — repeated reads inside the TTL do not re-run the sort query
    • fallback to the database when Redis is unavailable or errors
    • category filtering and clamped cache keys

Notes

  • The ordering column user_progress.totalPoints is already @Index()-backed, satisfying the index-backed ordering criterion.
  • main currently carries pre-existing lint/typecheck/build failures in unrelated files (e.g. src/rbac/roles/roles.controller.ts); this PR introduces no new failures.

closes #1159

@RUKAYAT-CODER
RUKAYAT-CODER merged commit c0a5a79 into rinafcode:main Aug 7, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cache leaderboard results and clamp the maximum limit in LeaderboardService

1 participant