ADR-007: File-Based API Response Cache

Decision Analysis and Resolution: REST API Response Caching

Created by: SW360 Architecture Team
Original Decision: 2026
Reformatted: April 2026
Status: Accepted
Estimated read time: 12 minutes


Table of Contents

  1. Background
  2. Goal
  3. Key Principles
  4. Key Inputs, Assumptions and Restrictions
  5. Options Analysis
  6. Criteria for Making a Decision
  7. Final Decision
  8. Implementation Details
  9. Contributors

Background

The SW360 REST API exposes resource-intensive endpoints that aggregate large amounts of data. The most critical example is GET /releases?allDetails=true, which:

  • Takes 3-5 minutes to complete, fetching and serializing thousands of releases with full details
  • Causes server resource competition when multiple concurrent requests are made
  • Can lead to server degradation or crashes requiring restarts
  • Impacts user experience significantly for common use cases like exporting data

Production Incidents:

  • Multiple concurrent allDetails=true requests have caused OutOfMemory errors
  • Server restarts required during high-usage periods
  • Users experience timeouts and abandoned requests

Why This Decision Matters: API performance directly affects user productivity and system stability. Without caching, every request pays the full computational cost.


Goal

The goal of this decision analysis is to:

  1. Dramatically reduce response time for expensive API endpoints
  2. Prevent server resource exhaustion from concurrent requests
  3. Maintain data consistency expectations
  4. Provide visibility into cache state for operations
  5. Enable opt-in adoption (disabled by default)

Key Principles

#PrincipleDescription
1Performance FirstCache hits should be orders of magnitude faster
2Memory SafetyAvoid JVM heap pressure from large responses
3Stale Data AcceptableUsers accept slightly stale data for speed
4Operational VisibilityProvide cache statistics and control
5Opt-InFeature disabled by default for safety

Key Inputs, Assumptions and Restrictions

TypeDescription
InputallDetails=true responses can be 100-500 MB
InputResponse generation takes 3-5 minutes
InputData changes infrequently (hours/days)
InputDifferent user roles see different data (security filtering)
AssumptionUsers accept data up to 24 hours stale
AssumptionSingle-instance deployments are primary target
RestrictionMust not introduce mandatory external dependencies
RestrictionMust maintain role-based security (different users, different data)

Options Analysis

Option 1 - Spring @Cacheable (In-Memory)

Summary

Use Spring’s built-in caching abstraction with annotations like @Cacheable. Cache the Java objects in JVM heap memory using providers like Caffeine or EhCache.

Conceptual View

graph TB
    subgraph SC["Spring @Cacheable"]
        direction TB
        A1["@Cacheable('releases')<br/>public List getAllReleases() { ... }"]
        A2["Cache Storage: JVM Heap Memory"]
        A3["Entry: Serialized Java objects (100-500 MB)"]
        A4["⚠️ Risk: OutOfMemoryError"]
    end

Impact / Changes Required

  • Add @Cacheable annotations to controller methods
  • Configure cache provider (Caffeine/EhCache)
  • Implement cache eviction on data mutations
  • Monitor heap usage carefully

SWOT Analysis

CategoryAnalysis
Strengths1. Simple annotation-based approach
2. Well-integrated with Spring
3. Fast in-memory access
4. Well-documented
Weaknesses1. Caches Java objects in heap—OOM risk for large responses
2. Cache lost on restart
3. Must deserialize on every read
4. Memory pressure from multiple cached endpoints
5. Difficult to cache different role variants
Opportunities1. Standard Spring pattern
Threats1. OutOfMemoryError from large cached responses
2. GC pressure degrading performance
3. Pod/container OOM kills

Option 2 - Redis/External Cache

Summary

Use Redis or another external caching system to store serialized responses. The cache lives outside the JVM, survives restarts, and can be shared across multiple instances.

Conceptual View

graph LR
    A[SW360 REST<br/>Instance 1] --> B[Redis Cache]
    C[SW360 REST<br/>Instance 2] --> B

Impact / Changes Required

  • Deploy and configure Redis cluster
  • Add Redis client dependency
  • Implement serialization layer
  • Configure network connectivity
  • Handle Redis availability

SWOT Analysis

CategoryAnalysis
Strengths1. Distributed across instances
2. Survives application restarts
3. Proven scalable solution
4. Rich features (TTL, pub/sub)
Weaknesses1. Additional infrastructure dependency
2. Network latency for cache access
3. Serialization overhead for large responses
4. Operational complexity (Redis HA)
5. Cost of running Redis cluster
Opportunities1. Could use for other caching needs
2. Shared cache for clustered SW360
Threats1. Redis unavailability affects caching
2. Network bandwidth for 100+ MB responses
3. Increased operational burden
4. Overkill for single-instance deployments

Option 3 - File-Based Response Cache

Summary

Cache pre-serialized JSON responses to disk files. Serve cached responses directly from disk without JVM heap involvement. Separate cache files per user role for security.

Conceptual View

graph TB
    subgraph FBC["File-Based Response Cache"]
        direction TB
        R["GET /releases?allDetails=true (ADMIN)"]
        R --> F["CacheReadFilter (Servlet Filter)"]
        F --> V["Resolve variant: ADMIN (from JWT)"]
        V --> CHK{"Check cache file"}
        CHK -->|HIT| S["Stream file to response (~10ms)"]
        CHK -->|MISS| C["Proceed to controller (3-5 min)"]
        FILES["Cache Files:<br/>/cache/releases-all-details-ADMIN.json (150 MB)<br/>/cache/releases-all-details-USER.json (120 MB)<br/>/cache/releases-all-details-CLEARING.json (140 MB)"]
    end

Impact / Changes Required

  • Implement servlet filter for cache reads
  • Implement ResponseBodyAdvice for cache writes
  • Create cache management infrastructure
  • Add admin endpoints for monitoring/invalidation
  • Configure disk space allocation

SWOT Analysis

CategoryAnalysis
Strengths1. No JVM heap pressure—files streamed directly
2. Cache survives restarts
3. No external dependencies
4. Per-role caching for security
5. Stale-while-revalidate pattern
6. Admin API for visibility
Weaknesses1. Disk I/O overhead
2. Not distributed across instances
3. More implementation effort
4. Disk space consumption
Opportunities1. Could extend to other endpoints
2. Efficient for large responses
3. Simple operational model
Threats1. Disk failure affects cache
2. SSD wear from frequent writes
3. Not suitable for clustered deployments

Option 4 - No Caching (Status Quo)

Summary

Continue without API response caching. Every request fully executes the controller logic and generates the complete response.

Conceptual View

graph TB
    subgraph NC["No Caching (Status Quo)"]
        direction TB
        N1["Every request: 3-5 minutes"]
        N2["Concurrent requests: Resource competition"]
        N3["Peak load: Server degradation/crashes"]
    end

Impact / Changes Required

  • No changes
  • Accept current performance limitations
  • Document workarounds for users

SWOT Analysis

CategoryAnalysis
Strengths1. No implementation effort
2. Always fresh data
3. No cache invalidation concerns
4. Simple architecture
Weaknesses1. 3-5 minute response times
2. Server stability issues
3. Poor user experience
4. Concurrent request competition
5. OutOfMemory crashes during export
Opportunities1. None—maintains problematic status quo
Threats1. Server crashes from concurrent heavy requests
2. User abandonment
3. Support burden
4. Reputation damage

Criteria for Making a Decision

T-Shirt Sizing Scale

T-Shirt SizeNumeric ValueMeaning
XS1.0Worst for this aspect
S2.5Poor
S-M3.75Below Average
M5.0Average
M-L6.25Above Average
L7.5Good
L-XL8.75Very Good
XL10.0Best for this aspect

Weighted Evaluation Matrix

CriteriaDescriptionWeightIn-MemoryRedisFile-BasedNo Cache
RatingScoreRatingScoreRatingScoreRatingScore
Memory SafetyAvoid OOM errors10XS10.0L75.0XL100.0S25.0
Performance GainResponse time improvement10L-XL87.5L75.0L-XL87.5XS10.0
No External DependenciesSelf-contained9XL90.0XS9.0XL90.0XL90.0
Cache PersistenceSurvives restarts7XS7.0XL70.0XL70.0N/A0.0
Role-Based VariantsPer-user-group caching8M40.0L60.0XL80.0N/A0.0
Implementation EffortDevelopment time7L-XL61.25M35.0M35.0XL70.0
Operational SimplicityMonitoring, maintenance7L52.5M35.0L52.5L-XL61.25
Stale-While-RevalidateServe stale during refresh6M30.0L45.0XL60.0N/A0.0
Server StabilityPrevent crashes9M45.0L-XL78.75L-XL78.75XS9.0
Large Response Handling100+ MB responses8XS8.0M-L50.0XL80.0M40.0
TOTAL431.25532.75733.75305.25

Score Summary

RankOptionTotal ScoreRecommendation
🥇 1File-Based Response Cache733.75SELECTED
🥈 2Redis/External Cache532.75Good for clustered deployments
🥉 3Spring @Cacheable431.25❌ OOM risk for large responses
4No Caching305.25❌ Unacceptable performance

Final Decision

Selected Option: File-Based Response Cache

Rationale

File-based caching was selected based on:

  1. Highest Weighted Score (733.75) - Best fit for SW360’s requirements

  2. Memory Safety (XL) - Critical advantage:

    • Large responses streamed directly from disk
    • No JVM heap involvement
    • Eliminates OOM risk that exists with in-memory caching
  3. No External Dependencies (XL) - Self-contained:

    • No Redis/Memcached infrastructure required
    • Simpler operational model
    • Suitable for single-instance deployments
  4. Role-Based Variants (XL) - Security maintained:

    • Separate cache files per UserGroup (ADMIN, USER, etc.)
    • Different users get appropriate filtered data
    • No security leakage between roles
  5. Large Response Handling (XL) - Designed for the problem:

    • 100-500 MB responses handled efficiently
    • Disk I/O is optimized for streaming
    • No serialization overhead on cache hits

Implementation Details

Architecture

graph TB
    A["GET /api/releases?allDetails=true (as ADMIN)"] --> B["CacheReadFilter (Servlet Filter)"]
    B --> C["Resolve variant: ADMIN (from JWT)"]
    C --> D{"Check cache:<br/>releases-all-details-ADMIN.json"}
    D -->|HIT| E["Stream JSON from disk (~10-50ms)"]
    D -->|MISS| F["ReleaseController.getReleasesForUser()"]
    F --> G["Execute business logic (3-5 minutes)"]
    G --> H["CachedResponseBodyAdvice.beforeBodyWrite()"]
    H --> I["Serialize response to JSON"]
    I --> J["Write to cache file (async)"]
    J --> K["Response sent"]
    E --> K

Key Components

ComponentResponsibility
CacheReadFilterServlet filter that serves cached JSON on HIT
CachedResponseBodyAdviceResponseBodyAdvice that writes to cache on MISS
@CachedResponseAnnotation for controller methods
CachedEndpointEnum of cacheable endpoints
CacheConditionInterface for request cacheability checks
ApiResponseCacheManagerCentral cache manager
FileBasedResponseCacheFile I/O, TTL, stale-while-revalidate
CacheAdminControllerAdmin REST endpoints
CacheVariantResolverResolves UserGroup from JWT

Configuration

# Global settings
rest.cache.enabled=true
rest.cache.directory=/var/sw360/cache

# Per-endpoint settings
rest.cache.releases-all-details.enabled=true
rest.cache.releases-all-details.ttl.seconds=86400
rest.cache.releases-all-details.max.stale.seconds=300
rest.cache.releases-all-details.per.role.caching=true

Admin API

EndpointMethodDescription
/api/admin/cache/statsGETStatistics for all endpoints
/api/admin/cache/stats/{endpoint}GETStatistics for specific endpoint
/api/admin/cacheDELETEInvalidate all caches
/api/admin/cache/{endpoint}DELETEInvalidate endpoint cache
/api/admin/cache/{endpoint}/{variant}DELETEInvalidate specific variant

Contributors

NameRoleContribution
SW360 Architecture TeamDecision MakersDesign and analysis
Development TeamImplementersImplementation
Operations TeamStakeholdersOperational requirements

Consequences Summary

Positive

  • ✅ Performance—cache hits served in ~10-50ms vs 3-5 minutes
  • ✅ Stability—no resource competition from concurrent requests
  • ✅ Memory safety—no risk of OOM from large cached responses
  • ✅ Persistence—cache survives application restarts
  • ✅ Visibility—per-variant statistics for monitoring
  • ✅ Security—per-role caching ensures appropriate data access
  • ✅ Extensibility—easy to add new cached endpoints

Negative

  • ⚠️ Disk usage—cache files consume disk space
  • ⚠️ Stale data—cache may serve stale data until TTL/invalidation
  • ⚠️ Single-instance—not shared across clustered deployments
  • ⚠️ Complexity—additional components to understand

Neutral

  • Automatic invalidation on data mutations (POST/PATCH/DELETE)
  • Filtered requests (with query params) not cached
  • Feature disabled by default (opt-in)

Revision History

VersionDateAuthorChanges
1.02026Architecture TeamInitial decision
2.0April 2026Bibhuti Bhusan DashReformatted to DAR/SWOT template