Cloudflare Caching Implementation Guide
Overview
This comprehensive guide covers the implementation, deployment, and management of a three-layer caching strategy using Cloudflare Cache API. This approach addresses performance issues identified in our analysis and provides a scalable, distributed caching solution.
Table of Contents
- Problem Statement & Solution
- Implementation Architecture
- Pre-Deployment Checklist
- Deployment Process
- Cloudflare Configuration
- Testing & Validation
- Performance Monitoring
- Troubleshooting
Problem Statement & Solution
Previous Memory Cache Issues
- Latency Penalty: +75ms average delay per request (+21.4% vs no-cache)
- Memory Overhead: In-function memory management causing processing delays
- Cache Isolation: No cache sharing between Edge Function invocations
- Cold Start Impact: Cache rebuilding on every cold start
- Limited Persistence: Cache lost between function restarts
Performance Analysis Results
Memory Cache Results:
- Average Response Time: 427.29ms (+21.4% vs no-cache)
- Throughput: 53.67 req/s (+187% vs no-cache)
- P95 Response Time: 549.44ms (+18.0% vs no-cache)
No-Cache Baseline:
- Average Response Time: 351.79ms
- Throughput: 18.67 req/s
- P95 Response Time: 465.63ms
Cloudflare Cache API Benefits
- Distributed Caching: Cache shared across Cloudflare's global edge network
- Reduced Memory Overhead: No in-function memory management
- Better Persistence: Cache survives function restarts and cold starts
- Geographic Distribution: Cache closer to users globally
- Native Integration: Optimized for Cloudflare Workers/Edge Functions
Implementation Architecture
Three-Layer Caching Strategy
Layer 1: Cloudflare Edge Cache
- Purpose: Global edge caching for maximum performance
- TTL: 5 minutes for API endpoints, 1 year for static assets
- Scope: All HTTP requests
Layer 2: Backend Cache Middleware
- Purpose: Application-level caching with ETag support
- TTL: Configurable (default: 5 minutes)
- Scope: FastAPI responses
Layer 3: Frontend Cache
- Purpose: Client-side caching for Supabase queries
- TTL: Short-lived with real-time invalidation
- Scope: Frontend API calls
Cache Key Strategy
Format: https://vertical-farm.goodgoodgreens.org/cache/{encoded_key}
Key Examples:
- Home Assistant Config: ha_config_{userId}
- Device States: ha_device_states_{userId}
- Entity Lists: ha_entities_{userId}
TTL Configuration
Data Type | TTL | Reasoning |
---|---|---|
HA Config | 5 minutes | Relatively stable configuration |
Device States | 30 seconds | Frequently changing sensor data |
Entity Lists | 10 minutes | Stable device/entity definitions |
Static Assets | 1 year | Immutable content |
API Endpoints | 5 minutes | Balance freshness and performance |
Pre-Deployment Checklist
✅ Backend Cache Middleware
- [ ]
cache_middleware.py
is implemented and tested - [ ] Cache middleware is added to FastAPI main.py
- [ ] Cache endpoints are accessible at
/api/v1/cache/*
- [ ] Environment variables are configured:
- [ ]
CACHE_ENABLED=true
- [ ]
CACHE_DEFAULT_TTL=300
- [ ]
CACHE_MAX_SIZE=1000
✅ Frontend Cache Implementation
- [ ]
supabase-cache.ts
is implemented - [ ] Frontend components are updated to use cached client
- [ ] Environment variables are configured:
- [ ]
NEXT_PUBLIC_CACHE_ENABLED=true
- [ ]
NEXT_PUBLIC_CACHE_DEBUG=false
(for production)
✅ Configuration Files
- [ ] Cloudflare configuration is documented
- [ ] Test script
test_caching.py
is available - [ ] Cache utilities are implemented
Deployment Process
Phase 1: Backend Deployment
# 1. Update backend dependencies (if needed)
cd backend
pip install -r requirements.txt
# 2. Test cache middleware locally
python -m pytest tests/ -v
# 3. Deploy backend with cache middleware
# (Use your existing deployment process)
Phase 2: Frontend Deployment
# 1. Update frontend dependencies
cd frontend
npm install
# 2. Build with caching enabled
npm run build
# 3. Deploy frontend
# (Use your existing deployment process)
Phase 3: Edge Function Deployment
# Deploy updated Edge Functions with Cloudflare Cache API
./scripts/deploy-cloudflare-cache.sh
Cloudflare Configuration
DNS and Proxy Setup
- [ ] Domain is proxied through Cloudflare (orange cloud icon)
- [ ] SSL/TLS is set to "Full (strict)"
- [ ] Always Use HTTPS is enabled
Page Rules Configuration
Apply these rules in order (higher priority first):
- Health Checks - No Cache
- URL:
*yourdomain.com/health*
-
Settings: Cache Level: Bypass
-
Static Assets - Aggressive Cache
- URL:
*yourdomain.com/static/*
-
Settings: Cache Level: Cache Everything, Edge Cache TTL: 1 year
-
API Endpoints - Short Cache
- URL:
*yourdomain.com/api/*
-
Settings: Cache Level: Cache Everything, Edge Cache TTL: 5 minutes
-
Main Application - Standard Cache
- URL:
*yourdomain.com/*
- Settings: Cache Level: Standard, Edge Cache TTL: 5 minutes
Transform Rules (Response Headers)
// Security Headers (All requests)
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
// API Cache Headers
Match: hostname eq "yourdomain.com" and starts_with(http.request.uri.path, "/api/")
Headers:
- Vary: Authorization, Accept-Encoding
- Cache-Control: public, max-age=300, must-revalidate
Speed Optimizations
- [ ] Auto Minify: HTML, CSS, JS enabled
- [ ] Brotli compression enabled
- [ ] HTTP/2 and HTTP/3 enabled
- [ ] Early Hints enabled
Cache Rules (Recommended)
Use Cloudflare Cache Rules for fine-grained control:
Rule: API Endpoint Caching
Match: hostname eq "vertical-farm.goodgoodgreens.org" and starts_with(uri.path, "/functions/v1/")
Action: Cache eligible resources
TTL: 300 seconds
Testing & Validation
Automated Testing
# From project root
python test_caching.py
# Performance tests
cd backend/app/tests/production_tests
node cloudflare-cache-performance-test.js
Manual Backend Testing
# Test cache health
curl https://yourdomain.com/api/v1/cache/health
# Test cache headers (look for X-Cache, ETag)
curl -I https://yourdomain.com/api/v1/farms
# Test ETag validation (should return 304)
ETAG=$(curl -s -I https://yourdomain.com/api/v1/farms | grep -i etag | cut -d' ' -f2)
curl -I -H "If-None-Match: $ETAG" https://yourdomain.com/api/v1/farms
Frontend Cache Testing
- [ ] Open browser dev tools
- [ ] Navigate to application
- [ ] Check console for cache debug messages
- [ ] Verify API responses show
fromCache: true
for repeated requests - [ ] Test real-time cache invalidation
Cloudflare Testing
- [ ] Check for
CF-Cache-Status
headers in responses - [ ] Monitor Cloudflare Analytics for cache hit rates
- [ ] Test cache purging via Cloudflare dashboard
- [ ] Verify security headers are applied
Performance Monitoring
Key Metrics to Track
Frontend Cache
- Cache hit rate (target: 85%+)
- Average response time for cached vs uncached requests
- Cache size and memory usage
Backend Cache
- Cache hit rate (target: 70%+)
- ETag validation rate
- Cache invalidation frequency
Cloudflare Cache
- Edge cache hit rate (target: 90%+ for static, 60%+ for API)
- Bandwidth savings
- Global response time improvements
Expected Performance Results
Metric | Memory Cache | Expected Cloudflare | Improvement |
---|---|---|---|
Avg Response Time | 427.29ms | ~380ms | -11% |
Throughput | 53.67 req/s | ~55 req/s | +3% |
P95 Response Time | 549.44ms | ~480ms | -13% |
Cache Hit Rate | Variable | >50% | Stable |
Monitoring Setup
# Backend cache stats endpoint
curl https://yourdomain.com/api/v1/cache/stats
# Frontend cache stats (in browser console)
console.log(supabaseWithCache.getCacheStats());
# Cloudflare analytics (dashboard)
# - Caching tab in Cloudflare dashboard
# - Analytics & Logs section
Edge Function Monitoring
Monitor for cache hit/miss patterns:
🎯 Cache HIT for key: ha_config_user123
❌ Cache MISS for key: ha_device_states_user456
💾 Cached data for key: ha_entities_user789 (TTL: 600s)
Cache Statistics Response
Response includes cache analytics:
{
"cache_stats": {
"hits": 45,
"misses": 23,
"totalRequests": 68,
"hitRate": 66.18,
"isEffective": true
},
"cache_type": "cloudflare_cache_api"
}
Troubleshooting
Common Issues
Cache Not Working
-
Check Environment Variables
# Backend echo $CACHE_ENABLED echo $CACHE_DEFAULT_TTL # Frontend echo $NEXT_PUBLIC_CACHE_ENABLED
-
Verify Middleware Order
- Cache middleware should be added after CORS
-
Check FastAPI middleware stack
-
Check Cache Statistics
curl https://yourdomain.com/api/v1/cache/stats
Stale Data Issues
- Verify Real-time Subscriptions
- Check Supabase real-time configuration
-
Test cache invalidation patterns
-
Check TTL Settings
- Review cache TTL configurations
- Test manual cache invalidation
Performance Issues
- Monitor Cache Hit Rates
- Target >50% for API endpoints
-
Target >90% for static assets
-
Check Geographic Distribution
- Verify Cloudflare edge locations
- Monitor regional performance
Configuration Issues
- Verify Cloudflare Rules
- Check Page Rules order and configuration
-
Validate Transform Rules syntax
-
Test Cache Headers
- Verify proper cache headers are set
- Check for conflicting cache directives
Debug Commands
# Check Cloudflare cache status
curl -I https://yourdomain.com/api/endpoint
# Purge specific cache entry
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
-d '{"files":["https://yourdomain.com/specific/endpoint"]}'
# Test cache effectiveness
ab -n 100 -c 10 https://yourdomain.com/api/endpoint
Implementation Code Snippets
Cloudflare Cache Utilities (cloudflare-cache-utils.ts
)
export class CloudflareCache {
static async get<T>(key: string): Promise<T | null> {
const cacheKey = new Request(`https://vertical-farm.goodgoodgreens.org/cache/${key}`);
const cached = await caches.default.match(cacheKey);
if (cached) {
return await cached.json();
}
return null;
}
static async set<T>(key: string, data: T, options?: CloudflareCacheOptions): Promise<void> {
const cacheKey = new Request(`https://vertical-farm.goodgoodgreens.org/cache/${key}`);
const response = new Response(JSON.stringify(data), {
headers: {
'Cache-Control': `public, max-age=${options?.ttl || 300}`,
'Content-Type': 'application/json'
}
});
await caches.default.put(cacheKey, response);
}
static async delete(key: string): Promise<boolean> {
const cacheKey = new Request(`https://vertical-farm.goodgoodgreens.org/cache/${key}`);
return await caches.default.delete(cacheKey);
}
static async getOrSet<T>(key: string, fetchFn: () => Promise<T>, ttl: number = 300): Promise<T> {
let data = await this.get<T>(key);
if (data === null) {
data = await fetchFn();
await this.set(key, data, { ttl });
}
return data;
}
}
export class HomeAssistantCloudflareCache {
static async setConfig(config: any, userId: string): Promise<void> {
await CloudflareCache.set(`ha_config_${userId}`, config, { ttl: 300 });
}
static async getConfig(userId: string): Promise<any | null> {
return await CloudflareCache.get(`ha_config_${userId}`);
}
static async setDeviceStates(deviceStates: Record<string, any>, userId: string): Promise<void> {
await CloudflareCache.set(`ha_device_states_${userId}`, deviceStates, { ttl: 30 });
}
static async getDeviceStates(userId: string): Promise<Record<string, any> | null> {
return await CloudflareCache.get(`ha_device_states_${userId}`);
}
}
Related Documentation
Last Updated: [Current Date] Consolidated from: CACHING_DEPLOYMENT_CHECKLIST.md, cloudflare-cache-implementation.md