Skip to main content

Phase 3 Plan: Performance Optimization

Objective: To ensure the dictionary feature is fast, scalable, and resilient under load by implementing a multi-layered caching strategy using Redis. This phase is critical for providing a production-ready, responsive user experience.

Key Tasks

  1. Caching Infrastructure Setup:
    • Integrate Redis into the application's infrastructure.
    • Configure the NestJS CacheModule to use redis-store as its primary cache store, making it available globally throughout the application.
  2. Layer 1: Automated Response Caching:
    • Apply the NestJS CacheInterceptor using the @UseInterceptors() decorator on all public, high-traffic GET endpoints.
    • Target Endpoints:
      • GET /languages
      • GET /dictionary/{lang-code}/{word}
      • GET /dictionary/search/{lang-code}
    • Define appropriate Time-to-Live (TTL) values for each endpoint's cache using @CacheTTL(). For example, a long TTL for /languages and a shorter TTL for search results.
  3. Layer 2: Granular Service-Level Caching:
    • Inject the CacheManager (@Inject(CACHE_MANAGER)) directly into the DictionaryService.
    • Identify computationally expensive or frequently accessed data queries within the service that are not fully covered by Layer 1 caching.
    • Primary Target: The logic that fetches and assembles the full declension and conjugation tables.
    • Implement manual caching: Before executing the database query, check if the result exists in the cache using cacheManager.get(). If not, execute the query and store the result using cacheManager.set() with a custom key (e.g., declension:{wordId}).
  4. Cache Invalidation Strategy:
    • Implement a robust cache invalidation mechanism to prevent stale data.
    • In the service logic for all administrative write endpoints (POST /words, PATCH /words/{id}, DELETE /words/{id}), manually and precisely delete the relevant cache keys from Redis using cacheManager.del().
    • Invalidation Targets: This must include both the Layer 1 response cache key (e.g., for GET /dictionary/de/Hund) and any associated Layer 2 granular cache keys (e.g., declension:{wordId}).
  5. Performance and Load Testing:
    • Use a load testing tool (e.g., k6, JMeter) to benchmark the performance of the primary lookup and search endpoints before and after implementing caching.
    • Simulate high-traffic scenarios to verify performance gains, measure the reduction in API latency, and confirm the decrease in database load.

Dependencies

  • Successful completion of Phase 1 and Phase 2.
  • A provisioned Redis instance accessible from the application environment.
  • Access to a load testing tool and environment.

Acceptance Criteria

  • Infrastructure: The NestJS application is successfully connected to and using Redis as its cache store.
  • Caching Functionality:
    • Making a second identical request to a cached GET endpoint returns a response significantly faster and does not trigger a new database query (verified via logging or monitoring).
    • The Redis database contains keys corresponding to both API responses and granular service-level data.
  • Invalidation:
    • Updating a word entry via the PATCH /words/{id} endpoint successfully deletes all related cache entries.
    • A subsequent GET request for that word retrieves the fresh, updated data from the database and re-populates the cache.
  • Performance Metrics:
    • Load testing demonstrates at least a 70% reduction in average response time for cached endpoints under load.
    • Database CPU and I/O metrics are measurably lower during load tests compared to the pre-caching baseline.