Skip to content

feat(#12): add Redis caching layer with graceful fallback - #47

Open
leanworld7-netizen wants to merge 2 commits into
EquipChain:mainfrom
leanworld7-netizen:feature/redis-cache-12
Open

feat(#12): add Redis caching layer with graceful fallback#47
leanworld7-netizen wants to merge 2 commits into
EquipChain:mainfrom
leanworld7-netizen:feature/redis-cache-12

Conversation

@leanworld7-netizen

Copy link
Copy Markdown

Summary

Closes #12 — implements Redis caching layer for blockchain data queries with graceful fallback.

Changes

src/services/cache.js (new, ~200 lines):

  • CacheService class wrapping ioredis with graceful degradation
  • get(key) — returns parsed JSON or null on miss/error
  • set(key, value, ttl) — stores with TTL via setex
  • del(key) — deletes single key
  • flush(pattern) — batch-deletes keys matching glob pattern (100-key batches)
  • invalidate(entity, id) — invalidates all cache entries for an entity
  • warm(entries) — pre-populates cache from fetcher functions
  • health() — returns connection status + hit/miss/error stats + hit rate
  • Key naming convention: equipchain:{entity}:{id}:{field}
  • TTL presets: meter=60s, config=300s, analytics=120s, default=60s
  • Retry strategy: exponential backoff, max 10 retries, capped at 2s
  • Falls back to no-cache mode when Redis unavailable (no crashes)

src/middleware/cache.js (new, ~80 lines):

  • cacheMiddleware(ttl) — Express middleware for automatic GET caching
  • Only caches GET requests, varies key by auth status
  • X-Cache: HIT|MISS and X-Cache-TTL response headers
  • Auto-detects TTL from path (/config=300s, /analytics=120s, /meter=60s)
  • invalidateCache(entity, id) — call after write operations

src/routes/index.js (modified):

  • Added cache health stats to /health endpoint

tests/unit/cache.test.js (new, 15 tests):

  • Tests all CRUD operations, TTL, flush, invalidate, warm, health
  • Graceful fallback when Redis disconnected
  • TTL preset values

package.json:

  • Added ioredis ^5.4.0

Testing

  • All 15 unit tests use a mock Redis client (no real Redis required)
  • Graceful fallback tested explicitly
  • Follows the spec's key naming convention and TTL defaults exactly

…n/analytics routes

- Create src/schemas/metering.schema.js with readingsQuerySchema,
  analyticsExportSchema, createReadingSchema, and bulkReadingsSchema
- Add validate() middleware to export route handlers
- Uncomment and mount admin + analytics routes in routes/index.js
  (schemas already existed but routes were never activated)
- Strict mode on body schemas to strip unexpected fields (anti-mass-assignment)

Closes EquipChain#8
- Create CacheService (src/services/cache.js) with ioredis:
  - get/set/del/flush/invalidate/warm methods
  - TTL presets: meter=60s, config=300s, analytics=120s
  - Exponential backoff retry (max 10, capped at 2s)
  - Graceful fallback when Redis is down (no-cache mode)
  - Health monitoring with hit/miss/error stats
  - Key naming: equipchain:{entity}:{id}:{field}

- Create caching middleware (src/middleware/cache.js):
  - Auto-cache GET responses with X-Cache headers
  - TTL auto-detection from path (/config=300s, /analytics=120s, /meter=60s)
  - Varies cache key by auth status
  - invalidateCache() helper for write-through invalidation

- Integrate cache health into /health endpoint
- Add ioredis ^5.4.0 to dependencies
- Add 15 unit tests covering all operations + fallback behavior

Closes EquipChain#12
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.

[Performance] Add Redis Caching Layer for Frequent Blockchain Data Queries

1 participant