This document describes the migration from problematic in-memory caching to a Redis-based distributed caching solution for the opensensor-api running in Kubernetes.
The original implementation used simple in-memory caching with global dictionaries:
# Problematic in-memory cache
_cache = {}
_cache_timestamps = {}- Pod Isolation: Each of the 4 replicas has its own memory space, so cached data isn't shared
- Cache Inconsistency: Different pods may have different cached values for the same data
- Memory Waste: Each pod duplicates the same cached data
- Pod Restarts: Cache is lost when pods restart (common in K8s)
- Scaling Issues: Adding more replicas multiplies memory usage and cache inconsistency
-
New Cache Module:
opensensor/cache.py- Redis connection management with connection pooling
- Graceful fallback when Redis is unavailable
- Comprehensive error handling and logging
-
Updated Collection APIs:
opensensor/collection_apis.py- Replaced
simple_cachedecorator withredis_cache - Updated
get_device_info_cachedfunction to use Redis
- Replaced
-
Cache Management Endpoints: Added to
opensensor/app.py/cache/stats- Get cache statistics/cache/clear- Clear all cache entries/cache/invalidate- Invalidate specific cache patterns
@redis_cache(ttl_seconds=300)
def get_device_info_cached(device_id: str):
"""Cached device information lookup using Redis"""
api_keys, _ = get_api_keys_by_device_id(device_id)
return reduce_api_keys_to_device_ids(api_keys, device_id)- If Redis is unavailable, functions execute without caching
- No service disruption when Redis is down
- Automatic reconnection attempts
- Uses existing
REDIS_URLenvironment variable - Connection pooling for optimal performance
- Health checks and timeout handling
REDIS_URL: Redis connection string (already available in deployment)
Added to Pipfile:
redis = "*"# Get cache statistics
GET /cache/statsResponse includes:
- Redis connection status
- Number of opensensor cache keys
- Redis version and memory usage
- Cache hit/miss ratios
# Clear all cache
POST /cache/clear
# Invalidate specific patterns
POST /cache/invalidate
{
"pattern": "get_device_info_cached:*"
}- Shared Cache: All pods share the same cache, ensuring consistency
- Persistence: Cache survives pod restarts
- Scalability: Adding more API pods doesn't duplicate cache data
- Performance: Redis is optimized for caching workloads
- Monitoring: Built-in metrics and monitoring capabilities
- Reliability: Graceful degradation when Redis is unavailable
- No changes required to existing deployment YAML
- Uses existing
REDIS_URLenvironment variable - Backward compatible - works with or without Redis
- Deploy new image with Redis caching
- Old in-memory cache will be gradually replaced
- No downtime or service interruption
- Check
/cache/statsendpoint for Redis connectivity - Monitor Redis metrics through existing infrastructure
- Log analysis for cache hit/miss ratios
# Install dependencies
pipenv install
# Set Redis URL (if testing locally)
export REDIS_URL="redis://localhost:6379"
# Run the application
uvicorn opensensor.app:app --reload# Check cache stats
curl -X GET "http://localhost:8000/cache/stats" \
-H "Authorization: Bearer <token>"
# Test cache invalidation
curl -X POST "http://localhost:8000/cache/invalidate" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"pattern": "*"}'- Add Redis dependency to Pipfile
- Create Redis cache utility module
- Replace in-memory caching in collection_apis.py
- Add cache management endpoints
- Update main app to include collection router
- Fix Pydantic v2 compatibility issues
- Document migration process
- Deploy to staging environment
- Verify Redis connectivity
- Monitor cache performance
- Deploy to production
If issues arise, the system gracefully falls back to no caching when Redis is unavailable. For complete rollback:
- Revert to previous image version
- In-memory caching will resume automatically
- No data loss or service interruption
- Cache Hit Ratio: Expected 80-90% for device info lookups
- Response Time: 10-50ms improvement for cached requests
- Memory Usage: Reduced per-pod memory usage
- Consistency: 100% cache consistency across all pods