Files
yourwillyourwish/docs/REDIS_SETUP.md
2026-02-06 21:44:04 -06:00

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_PASSWORD environment 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

# 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:

  1. Verify Redis is running: redis-cli ping
  2. Check REDIS_URL environment variable
  3. Ensure Redis port isn't blocked by firewall
  4. Restart Docker: docker-compose restart redis

Cache Not Working

Issue: Cache operations failing silently

Solution:

  1. Check Redis logs: docker-compose logs redis
  2. Verify connectivity: docker-compose exec redis redis-cli ping
  3. Check error logs in application console
  4. Verify cache keys are correctly formatted

Memory Issues

Issue: Redis using too much memory

Solution:

  1. Enable TTL on all cache operations
  2. Implement cache invalidation patterns
  3. Use invalidateCachePattern() to clean up old data
  4. Monitor with redis-cli INFO memory

Session Not Persisting

Issue: Sessions expire too quickly or not at all

Solution:

  1. Verify TTL is set correctly (default: 7 days = 604800 seconds)
  2. Check REDIS_URL is correct
  3. Ensure Redis persistence is enabled (AOF)
  4. Verify no concurrent invalidation calls

Production Deployment

Security Best Practices

  1. Change default password:

    REDIS_PASSWORD=your_strong_password_here
    
  2. Use Redis with authentication:

    REDIS_URL=redis://:your_password@your-redis-host:6379
    
  3. Enable SSL/TLS:

    REDIS_URL=rediss://:your_password@your-redis-host:6380
    
  4. 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:

  1. Check Redis logs: docker-compose logs redis
  2. Verify connection: redis-cli ping
  3. Review error messages in application logs
  4. Check the troubleshooting section above