Skip to content

feat(caching): improve cache warming with limits, batching, metrics, …#1080

Open
abdulazizishaq212-prog wants to merge 1 commit into
rinafcode:mainfrom
abdulazizishaq212-prog:feat/cache-warming-improvements
Open

feat(caching): improve cache warming with limits, batching, metrics, …#1080
abdulazizishaq212-prog wants to merge 1 commit into
rinafcode:mainfrom
abdulazizishaq212-prog:feat/cache-warming-improvements

Conversation

@abdulazizishaq212-prog

Copy link
Copy Markdown

Addresses five weaknesses in the cache warming pipeline: unbounded DB reads, unweighted entry selection, burst Redis
writes, no observability, and warming that competed with the boot sequence.

Changes

Configurable entry ceiling (CACHE_WARM_MAX_ENTRIES)

Every DB read in the warming pipeline now has an explicit take / limit derived from CACHE_WARMING.MAX_ENTRIES (default
500, overridable via CACHE_WARM_MAX_ENTRIES). Previously, warmCoursesList issued an unbounded find against the courses
table.

Real-signal prioritisation

  • Courses list — ranked by enrollment count descending (same signal used by popular courses), with a createdAt DESC
    recency fallback when the enrollment table is empty.
  • User profiles — ranked by lastLoginAt DESC so the most recently active users fill the warmed set; falls back to
    updatedAt DESC for fresh installs or seed data.

Batched processing with inter-batch delay

warmUserProfiles now processes the working set in slices of CACHE_WARMING.BATCH_SIZE (default 50, env:
CACHE_WARM_BATCH_SIZE), with a CACHE_WARMING.BATCH_DELAY_MS pause (default 50 ms, env: CACHE_WARM_BATCH_DELAY_MS)
between batches. This bounds peak Redis write throughput and heap allocation per warming cycle.

Prometheus metrics

Two new instruments added to MetricsCollectionService:

  • cache_warming_entries_total — Counter, labelled by target — total keys written per warming run.
  • cache_warming_duration_seconds — Histogram, labelled by target — wall-clock duration per run.

Every warm* method calls metrics.recordCacheWarming(target, keysWarmed, durationMs) after completing.

Deferred startup warming

CacheWarmingScheduler now implements OnApplicationBootstrap instead of OnModuleInit. NestJS fires onApplicationBootstrap
after the HTTP server is listening, so warming no longer competes with the tail end of the boot sequence. An additional
CACHE_WARMING.STARTUP_DELAY_MS grace period (default 5 s, env: CACHE_WARM_STARTUP_DELAY_MS) further defers the first
warmAll() call.

Environment variables (all optional)

┌─────────────────────────────┬─────────┬──────────────────────────────────────────┐
│ Variable │ Default │ Description │
├─────────────────────────────┼─────────┼──────────────────────────────────────────┤
│ CACHE_WARM_MAX_ENTRIES │ 500 │ Max rows fetched per warming target │
├─────────────────────────────┼─────────┼──────────────────────────────────────────┤
│ CACHE_WARM_BATCH_SIZE │ 50 │ User profiles processed per batch │
├─────────────────────────────┼─────────┼──────────────────────────────────────────┤
│ CACHE_WARM_BATCH_DELAY_MS │ 50 │ Delay between profile batches (ms) │
├─────────────────────────────┼─────────┼──────────────────────────────────────────┤
│ CACHE_WARM_STARTUP_DELAY_MS │ 5000 │ Grace period before startup warm-up (ms) │
└─────────────────────────────┴─────────┴──────────────────────────────────────────┘

Testing

  • All 15 unit tests pass (pnpm jest cache-warming).
  • New tests cover: enrollment-count prioritisation, recency fallback, BATCH_SIZE enforcement (via fake timers), deferred
    startup delay assertion.
  • Build passes (pnpm build).

Files changed

  • src/caching/caching.constants.ts
  • src/caching/cache-warming.service.ts
  • src/caching/cache-warming.scheduler.ts
  • src/monitoring/metrics/metrics-collection.service.ts
  • src/caching/cache-warming.service.spec.ts
  • src/caching/cache-warming.scheduler.spec.ts

closes #1053

…and deferred startup

- Add CACHE_WARM_MAX_ENTRIES, BATCH_SIZE, BATCH_DELAY_MS, STARTUP_DELAY_MS
  to CACHE_WARMING constants (all env-var configurable with safe defaults)
- Prioritise warmCoursesList by enrollment count with recency fallback
- Prioritise warmUserProfiles by lastLoginAt recency with updatedAt fallback
- Process user profiles in configurable batches with inter-batch delay to
  bound DB and memory pressure
- Emit cache_warming_entries_total (Counter) and cache_warming_duration_seconds
  (Histogram) Prometheus metrics via MetricsCollectionService
- Defer startup warming until after the server is accepting traffic by
  switching OnModuleInit to OnApplicationBootstrap + STARTUP_DELAY_MS pause
- Update specs: MetricsCollectionService mock, enrollment-priority/fallback
  tests, batch-size assertion with fake timers, deferred-startup delay tests
@drips-wave

drips-wave Bot commented Jul 25, 2026

Copy link
Copy Markdown

@abdulazizishaq212-prog Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@RUKAYAT-CODER

Copy link
Copy Markdown
Contributor

Well done on the job done so far!
Kindly fix workflow to pass.

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.

Bound the cache warming repository reads in CacheWarmingService

2 participants