Comprehensive Caching Implementation Guide
This guide documents the complete three-layer caching strategy implemented for the vertical-farm application.
Overview
The caching implementation consists of three complementary layers:
- Frontend Supabase Query Caching - Client-side caching with real-time invalidation
- Backend Response Caching - Server-side middleware with ETag support
- Cloudflare CDN Caching - Edge caching with global distribution
Layer 1: Frontend Supabase Query Caching
Implementation: frontend/src/lib/supabase-cache.ts
Features: - In-memory caching with configurable TTL - localStorage persistence for cross-session caching - Stale-while-revalidate strategy - Real-time cache invalidation via Supabase subscriptions - LRU eviction and size limits
Cache Strategies:
- Farms: 10 minutes TTL, 2 minutes stale time
- Farm Hierarchy: 15 minutes TTL, 2 minutes stale time
- Device Assignments: 5 minutes TTL, 30 seconds stale time
Usage Example:
import { supabaseWithCache } from '@/lib/supabase-cache';
// Cached farm data with automatic invalidation
const farms = await supabaseWithCache.getFarmsWithCache(userId);
// Cached hierarchy with real-time updates
const hierarchy = await supabaseWithCache.getFarmHierarchyWithCache(farmId);
Real-time Invalidation: - Automatically invalidates cache when database changes occur - Uses Supabase real-time subscriptions for instant updates - Pattern-based invalidation for related data
Layer 2: Backend Response Caching
Implementation: backend/app/middleware/cache_middleware.py
Features: - In-memory response caching with configurable TTL - ETag generation and validation for efficient revalidation - Automatic cache invalidation on data mutations - User-specific caching support - Cache statistics and monitoring
Cache TTL Configuration:
CACHE_SETTINGS = {
"/api/v1/farms": 300, # 5 minutes
"/api/v1/farms/hierarchy": 900, # 15 minutes
"/api/v1/devices": 180, # 3 minutes
"/api/v1/user/profile": 1800, # 30 minutes
}
ETag Support:
- Generates ETags based on response content hash
- Supports If-None-Match
headers for 304 responses
- Reduces bandwidth usage for unchanged data
Integration:
# Added to FastAPI main.py
from app.middleware.cache_middleware import ResponseCacheMiddleware
app.add_middleware(ResponseCacheMiddleware)
Layer 3: Cloudflare CDN Caching
Configuration: cloudflare-config.txt
Page Rules (Priority Order):
- Health Checks - No cache
- URL:
*vertical-farm.goodgoodgreens.org/health*
-
Cache Level: Bypass
-
Static Assets - Aggressive cache
- URL:
*vertical-farm.goodgoodgreens.org/static/*
- Edge Cache TTL: 1 year
-
Browser Cache TTL: 1 year
-
API Endpoints - Short cache with revalidation
- URL:
*vertical-farm.goodgoodgreens.org/api/*
- Edge Cache TTL: 5 minutes
- Origin Cache Control: On
Transform Rules: - Security headers for all requests - Cache-Control headers for different content types - Vary headers for proper cache segmentation
Optional Workers: - Custom caching logic for specific endpoints - Advanced cache invalidation strategies - Real-time data handling
Cache Invalidation Strategy
Frontend Cache Invalidation
// Pattern-based invalidation
supabaseWithCache.invalidateCache('farms:');
// Specific key invalidation
supabaseWithCache.invalidateCache('farm-hierarchy:123');
// Real-time automatic invalidation via subscriptions
Backend Cache Invalidation
# Automatic invalidation on mutations
@app.post("/api/v1/farms")
async def create_farm(farm_data: FarmCreate):
result = await create_farm_service(farm_data)
# Cache automatically invalidated by middleware
return result
Cloudflare Cache Invalidation
# Purge specific URLs
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
--data '{"files":["https://vertical-farm.goodgoodgreens.org/api/v1/farms"]}'
# Purge by cache tags (if using Workers)
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
--data '{"tags":["farms","devices"]}'
Performance Benefits
Expected Performance Improvements
Frontend Caching: - 80-90% reduction in database queries for repeated data - Sub-100ms response times for cached data - Improved user experience with instant data loading
Backend Caching: - 60-70% reduction in database load - 304 responses reduce bandwidth by 90% - Faster API response times (50-200ms vs 200-500ms)
Cloudflare Caching: - Global edge caching reduces latency by 50-80% - Reduced origin server load by 70-80% - Improved availability during traffic spikes
Cache Hit Rate Targets
- Frontend cache: 85%+ hit rate
- Backend cache: 70%+ hit rate
- Cloudflare cache: 90%+ hit rate for static content, 60%+ for API
Monitoring and Debugging
Frontend Cache Statistics
const stats = supabaseWithCache.getCacheStats();
console.log('Cache hit rate:', stats.hitRate);
console.log('Cache size:', stats.size);
console.log('Cache entries:', stats.entries);
Backend Cache Monitoring
# Cache statistics endpoint
@app.get("/api/v1/cache/stats")
async def get_cache_stats():
return cache_middleware.get_stats()
Cloudflare Analytics
- Monitor cache hit ratios in Cloudflare dashboard
- Track bandwidth savings and performance improvements
- Set up alerts for cache performance degradation
Configuration Management
Environment Variables
# Frontend (.env.local)
NEXT_PUBLIC_CACHE_ENABLED=true
NEXT_PUBLIC_CACHE_DEBUG=false
# Backend (.env)
CACHE_ENABLED=true
CACHE_DEFAULT_TTL=300
CACHE_MAX_SIZE=1000
Feature Flags
// Disable caching for development/debugging
const cacheConfig = {
enabled: process.env.NEXT_PUBLIC_CACHE_ENABLED === 'true',
debug: process.env.NEXT_PUBLIC_CACHE_DEBUG === 'true'
};
Testing Strategy
Frontend Cache Testing
// Test cache hit/miss behavior
describe('Supabase Cache', () => {
it('should cache farm data', async () => {
const farms1 = await supabaseWithCache.getFarmsWithCache();
const farms2 = await supabaseWithCache.getFarmsWithCache();
expect(farms2.fromCache).toBe(true);
});
});
Backend Cache Testing
# Test ETag generation and validation
def test_etag_caching():
response1 = client.get("/api/v1/farms")
etag = response1.headers["etag"]
response2 = client.get("/api/v1/farms", headers={"If-None-Match": etag})
assert response2.status_code == 304
Load Testing
# Test cache performance under load
ab -n 1000 -c 10 https://vertical-farm.goodgoodgreens.org/api/v1/farms
Troubleshooting
Common Issues
Cache Not Working: 1. Check environment variables 2. Verify middleware order 3. Check cache TTL settings 4. Monitor cache statistics
Stale Data: 1. Verify real-time subscriptions 2. Check cache invalidation patterns 3. Review TTL settings 4. Test manual invalidation
Performance Issues: 1. Monitor cache hit rates 2. Check cache size limits 3. Review eviction policies 4. Optimize cache keys
Debug Tools
// Enable cache debugging
localStorage.setItem('cache-debug', 'true');
// View cache contents
console.log(supabaseWithCache.getCacheStats());
Future Enhancements
Planned Improvements
- Redis Integration - Shared cache across backend instances
- Cache Warming - Preload frequently accessed data
- Smart Invalidation - ML-based cache invalidation
- Compression - Compress cached responses
- Metrics Dashboard - Real-time cache performance monitoring
Advanced Features
- Distributed Caching - Multi-region cache synchronization
- Cache Partitioning - User-specific cache isolation
- Predictive Caching - Preload data based on user behavior
- Cache Analytics - Detailed performance insights
Conclusion
This three-layer caching implementation provides: - Improved Performance - Faster response times and reduced latency - Reduced Load - Lower database and server resource usage - Better UX - Instant data loading and improved responsiveness - Scalability - Support for increased user load - Cost Efficiency - Reduced bandwidth and server costs
The implementation is production-ready and includes comprehensive monitoring, debugging tools, and invalidation strategies to ensure data consistency while maximizing performance benefits.