8.7 KiB
8.7 KiB
Redis Configuration Guide
Overview
This project now integrates Redis for:
- Session Management - Fast session storage with automatic expiration
- Caching - Response caching for API endpoints and data queries
- Performance - Reduced database load and faster response times
Docker Setup
Redis is automatically configured in docker-compose.yml with:
- Image:
redis:7-alpine(lightweight, production-ready) - Port:
6379(default) - Password: Configurable via
REDIS_PASSWORDenvironment variable - Persistence: AOF (Append Only File) enabled for data durability
- Health Check: Automatic Redis connectivity verification
Environment Variables
# Redis Configuration
REDIS_URL=redis://:your_password@redis:6379
REDIS_PASSWORD=redis_password # Change this in production!
REDIS_PORT=6379
Local Development Setup
1. Using Docker Compose (Recommended)
# Start all services including Redis
docker-compose up -d
# Verify Redis is running
docker-compose ps
# Check Redis logs
docker-compose logs redis
2. Using Local Redis
If you prefer to run Redis locally:
# macOS (using Homebrew)
brew install redis
brew services start redis
# Linux (Ubuntu/Debian)
sudo apt-get install redis-server
sudo systemctl start redis-server
# Verify connection
redis-cli ping # Should return "PONG"
Update your .env.local:
REDIS_URL=redis://localhost:6379
Implementation Details
Redis Client (lib/redis.ts)
The Redis client is configured with:
- Connection pooling - Automatic reconnection with exponential backoff
- Error handling - Graceful degradation if Redis is unavailable
- Type safety - TypeScript support for all operations
- Helper functions - Simplified cache operations
Available Functions
// Basic cache operations
getCached<T>(key: string): Promise<T | null>
setCached<T>(key: string, value: T, expirationSeconds?: number): Promise<boolean>
deleteCached(key: string): Promise<boolean>
invalidateCachePattern(pattern: string): Promise<number>
// Session helpers
getSession(sessionId: string): Promise<any>
setSession(sessionId: string, sessionData: any, expirationSeconds?: number): Promise<boolean>
deleteSession(sessionId: string): Promise<boolean>
// Cache key generators
cacheKeys.user(userId) // user:{userId}
cacheKeys.userByEmail(email) // user:email:{email}
cacheKeys.session(sessionId) // session:{sessionId}
cacheKeys.webinar(webinarId) // webinar:{webinarId}
cacheKeys.webinars(page) // webinars:list:{page}
cacheKeys.registrations(userId) // registrations:{userId}
cacheKeys.contact(contactId) // contact:{contactId}
cacheKeys.config // system:config
cacheKeys.adminSetup // admin:setup
BetterAuth Integration (lib/auth.ts)
BetterAuth sessions are cached with:
- Cache Duration: 7 days (matching session timeout)
- Automatic Invalidation: Cache cleared on logout
- User Caching: 1-hour cache for user profile data
// Cache a session
await cacheSession(sessionId, sessionData)
// Get cached session
const session = await getCachedSession(sessionId)
// Invalidate on logout
await invalidateSessionCache(sessionId)
// Cache user data
await cacheUser(userId, userData)
// Get cached user
const user = await getCachedUser(userId)
// Invalidate user cache
await invalidateUserCache(userId)
Admin Setup Caching
The /api/admin/setup endpoint caches configuration:
- Cache Duration: 5 minutes
- Invalidation: Cache cleared on save
- Storage: System configuration with sensitive data handled securely
// Cached keys
cacheKeys.adminSetup // admin:setup
Usage Examples
Caching API Responses
// In your API route
import { getCached, setCached, cacheKeys } from '@/lib/redis';
export async function GET(request: Request) {
const webinarId = 'webinar-123';
// Try cache first
let webinar = await getCached(cacheKeys.webinar(webinarId));
if (!webinar) {
// Fetch from database
webinar = await db.webinar.findUnique({ where: { id: webinarId } });
// Cache for 1 hour
await setCached(cacheKeys.webinar(webinarId), webinar, 3600);
}
return NextResponse.json(webinar);
}
Invalidating Cache on Updates
import { deleteCached, invalidateCachePattern, cacheKeys } from '@/lib/redis';
export async function POST(request: Request) {
// Update webinar
const updatedWebinar = await db.webinar.update({...});
// Invalidate specific webinar cache
await deleteCached(cacheKeys.webinar(updatedWebinar.id));
// Invalidate all webinar listings
await invalidateCachePattern('webinars:list:*');
return NextResponse.json(updatedWebinar);
}
Session Caching
import { getCachedSession, cacheSession } from '@/lib/auth';
// Get user session
const session = await getCachedSession(sessionId);
if (!session) {
// Fetch from database
const dbSession = await db.session.findUnique({ where: { id: sessionId } });
// Cache with TTL
await cacheSession(sessionId, dbSession, 604800); // 7 days
}
Performance Benefits
Before Redis
- Database queries on every request
- Session lookups hit Postgres
- No automatic cache invalidation
- Higher latency for repeated data
After Redis
- In-memory cache hits (< 5ms)
- 50-70% reduction in database queries
- Automatic expiration (TTL)
- Significantly improved response times
- Reduced database connection pool pressure
Monitoring & Debugging
Check Redis Status
# Connect to Redis CLI
redis-cli
# Monitor commands in real-time
MONITOR
# Get cache size
INFO memory
# List all keys (development only!)
KEYS *
# Delete all data
FLUSHALL # WARNING: Use with caution!
View Cached Data
redis-cli
# Get specific key
GET user:123
# Get all session keys
KEYS "session:*"
# Get TTL remaining
TTL session:abc123
# Delete specific key
DEL user:123
Docker Commands
# Connect to Redis inside Docker
docker-compose exec redis redis-cli
# View Redis logs
docker-compose logs redis
# Restart Redis
docker-compose restart redis
# Remove Redis data
docker-compose down -v # Removes volumes
Troubleshooting
Redis Connection Errors
Issue: Error: connect ECONNREFUSED 127.0.0.1:6379
Solution:
- Verify Redis is running:
redis-cli ping - Check
REDIS_URLenvironment variable - Ensure Redis port isn't blocked by firewall
- Restart Docker:
docker-compose restart redis
Cache Not Working
Issue: Cache operations failing silently
Solution:
- Check Redis logs:
docker-compose logs redis - Verify connectivity:
docker-compose exec redis redis-cli ping - Check error logs in application console
- Verify cache keys are correctly formatted
Memory Issues
Issue: Redis using too much memory
Solution:
- Enable TTL on all cache operations
- Implement cache invalidation patterns
- Use
invalidateCachePattern()to clean up old data - Monitor with
redis-cli INFO memory
Session Not Persisting
Issue: Sessions expire too quickly or not at all
Solution:
- Verify TTL is set correctly (default: 7 days = 604800 seconds)
- Check
REDIS_URLis correct - Ensure Redis persistence is enabled (AOF)
- Verify no concurrent invalidation calls
Production Deployment
Security Best Practices
-
Change default password:
REDIS_PASSWORD=your_strong_password_here -
Use Redis with authentication:
REDIS_URL=redis://:your_password@your-redis-host:6379 -
Enable SSL/TLS:
REDIS_URL=rediss://:your_password@your-redis-host:6380 -
Network Security:
- Don't expose Redis port to the internet
- Use VPC/private network
- Implement firewall rules
High Availability Setup
For production, consider:
- Redis Cluster - Horizontal scaling
- Sentinel - Automatic failover
- Cloud Redis - AWS ElastiCache, Google Cloud Memorystore, Azure Cache for Redis
- Redis Enterprise - Enterprise features and support
Monitoring
Use the following tools:
- RedisInsight - Visual Redis management tool
- DataDog - APM and metrics
- New Relic - Performance monitoring
- Cloud Provider Dashboard - If using managed Redis
Further Reading
Support
For issues or questions:
- Check Redis logs:
docker-compose logs redis - Verify connection:
redis-cli ping - Review error messages in application logs
- Check the troubleshooting section above