Skip to content

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

  1. Problem Statement & Solution
  2. Implementation Architecture
  3. Pre-Deployment Checklist
  4. Deployment Process
  5. Cloudflare Configuration
  6. Testing & Validation
  7. Performance Monitoring
  8. 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

  1. Distributed Caching: Cache shared across Cloudflare's global edge network
  2. Reduced Memory Overhead: No in-function memory management
  3. Better Persistence: Cache survives function restarts and cold starts
  4. Geographic Distribution: Cache closer to users globally
  5. 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):

  1. Health Checks - No Cache
  2. URL: *yourdomain.com/health*
  3. Settings: Cache Level: Bypass

  4. Static Assets - Aggressive Cache

  5. URL: *yourdomain.com/static/*
  6. Settings: Cache Level: Cache Everything, Edge Cache TTL: 1 year

  7. API Endpoints - Short Cache

  8. URL: *yourdomain.com/api/*
  9. Settings: Cache Level: Cache Everything, Edge Cache TTL: 5 minutes

  10. Main Application - Standard Cache

  11. URL: *yourdomain.com/*
  12. 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

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

  1. Check Environment Variables

    # Backend
    echo $CACHE_ENABLED
    echo $CACHE_DEFAULT_TTL
    
    # Frontend
    echo $NEXT_PUBLIC_CACHE_ENABLED
    

  2. Verify Middleware Order

  3. Cache middleware should be added after CORS
  4. Check FastAPI middleware stack

  5. Check Cache Statistics

    curl https://yourdomain.com/api/v1/cache/stats
    

Stale Data Issues

  1. Verify Real-time Subscriptions
  2. Check Supabase real-time configuration
  3. Test cache invalidation patterns

  4. Check TTL Settings

  5. Review cache TTL configurations
  6. Test manual cache invalidation

Performance Issues

  1. Monitor Cache Hit Rates
  2. Target >50% for API endpoints
  3. Target >90% for static assets

  4. Check Geographic Distribution

  5. Verify Cloudflare edge locations
  6. Monitor regional performance

Configuration Issues

  1. Verify Cloudflare Rules
  2. Check Page Rules order and configuration
  3. Validate Transform Rules syntax

  4. Test Cache Headers

  5. Verify proper cache headers are set
  6. 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}`);
  }
}

Last Updated: [Current Date] Consolidated from: CACHING_DEPLOYMENT_CHECKLIST.md, cloudflare-cache-implementation.md