Skip to content

Latest commit

 

History

History
518 lines (399 loc) · 12.1 KB

File metadata and controls

518 lines (399 loc) · 12.1 KB

Issue #852: Redis-Based Session Sharing - COMPLETED ✅

Summary

Successfully implemented Redis-based session sharing across serverless instances with connection pooling, health monitoring, and automatic fallback to in-memory storage.

Acceptance Criteria - All Met ✅

✅ Implement Redis adapter as default for production environments

Implementation:

  • Redis client manager with singleton pattern
  • Automatic detection of production environment
  • Redis used by default when REDIS_URL is configured
  • Logs warnings in production when Redis is not configured

Files:

  • app/api/jobs/shared/redisClient.ts - Redis client manager
  • app/api/jobs/shared/jobRepository.ts - Updated to use Redis manager

✅ Add health check for Redis connection

Implementation:

  • Built-in health check with ping mechanism
  • Detailed health metrics tracking
  • HTTP endpoint for monitoring
  • Periodic health checks every 30 seconds (configurable)

Files:

  • app/api/jobs/shared/redisClient.ts - Health check functions
  • app/api/health/redis/route.ts - HTTP health endpoint

✅ Implement fallback to in-memory storage if Redis is unavailable

Implementation:

  • Automatic fallback on connection failure
  • Fallback on health check failure
  • Fallback after max reconnection attempts
  • Graceful degradation with logging

Files:

  • app/api/jobs/shared/jobRepository.ts - Fallback logic
  • app/api/jobs/shared/redisClient.ts - Availability checks

✅ Add Redis connection pooling for better performance

Implementation:

  • Connection pooling with configurable parameters
  • Keep-alive for persistent connections
  • Offline command queueing
  • Pool statistics and metrics

Files:

  • app/api/jobs/shared/redisClient.ts - Connection pool configuration

✅ Document Redis configuration requirements

Implementation:

  • Comprehensive documentation with examples
  • Configuration guide for multiple providers
  • Troubleshooting section
  • Best practices and deployment guides

Files:

  • docs/REDIS_SESSION_SHARING.md - Complete documentation

Technical Implementation

Core Components

  1. Redis Client Manager (app/api/jobs/shared/redisClient.ts)

    • Singleton Redis client with connection pooling
    • Automatic reconnection with exponential backoff
    • Health monitoring and metrics
    • Event listeners for connection state
    • Graceful shutdown handlers
  2. Enhanced Job Repository (app/api/jobs/shared/jobRepository.ts)

    • Updated to use Redis client manager
    • Automatic fallback to in-memory storage
    • Error handling with proper logging
    • Support for both storage adapters
  3. Health Check Endpoint (app/api/health/redis/route.ts)

    • Real-time health status
    • Pool metrics and statistics
    • Fallback status indication
    • Proper HTTP status codes
  4. Comprehensive Testing

    • Redis client manager tests
    • Health endpoint tests
    • Updated job repository tests
    • Mock implementations for testing

Configuration Options

Environment Variables Added:

REDIS_URL=redis://:password@hostname:6379
REDIS_MAX_RETRIES=3
REDIS_RETRY_DELAY=1000
REDIS_CONNECT_TIMEOUT=10000
REDIS_COMMAND_TIMEOUT=5000
REDIS_KEEP_ALIVE=30000
REDIS_MAX_RECONNECT_ATTEMPTS=10
REDIS_HEALTH_CHECK_INTERVAL=30000

Key Features

  1. Connection Pooling

    • Optimized for serverless environments
    • Configurable pool parameters
    • Keep-alive for persistent connections
    • Offline command queueing
  2. Health Monitoring

    • Automatic health checks
    • Detailed metrics tracking
    • Real-time status updates
    • HTTP monitoring endpoint
  3. Automatic Reconnection

    • Exponential backoff strategy
    • Configurable max attempts
    • Connection state tracking
    • Graceful degradation
  4. Fallback Mechanism

    • Automatic detection of Redis unavailability
    • Seamless fallback to in-memory storage
    • No application code changes required
    • Proper logging and warnings
  5. Error Handling

    • Comprehensive error logging
    • Proper error propagation
    • Recovery mechanisms
    • User-friendly error messages

Installation & Setup

1. Configure Redis URL

Development:

REDIS_URL=redis://localhost:6379

Production (with TLS):

REDIS_URL=rediss://:password@your-redis-host:6380

2. Optional Configuration

# Increase timeouts for slow networks
REDIS_CONNECT_TIMEOUT=15000
REDIS_COMMAND_TIMEOUT=10000

# More aggressive reconnection
REDIS_MAX_RECONNECT_ATTEMPTS=20
REDIS_RETRY_DELAY=500

# More frequent health checks
REDIS_HEALTH_CHECK_INTERVAL=15000

3. Verify Configuration

# Check Redis health
curl http://localhost:3000/api/health/redis

# Expected response (healthy):
{
  "status": "healthy",
  "redis": {
    "available": true,
    "isHealthy": true,
    "status": "connected"
  },
  "pool": {
    "connectedClients": 5,
    "usedMemory": "1.5M",
    "uptimeSeconds": 3600
  }
}

Usage Examples

Basic Usage (No Code Changes)

import { jobStore } from '@/app/api/jobs/shared/jobStore';

// Works with Redis OR in-memory storage automatically
const job = await jobStore.get('job-123');

Health Check

import { checkRedisHealth } from '@/app/api/jobs/shared/redisClient';

if (await checkRedisHealth()) {
  console.log('Redis is healthy');
}

Get Metrics

import { getRedisHealthMetrics } from '@/app/api/jobs/shared/redisClient';

const metrics = await getRedisHealthMetrics();
console.log(`Status: ${metrics.status}`);
console.log(`Uptime: ${metrics.uptime}ms`);
console.log(`Healthy: ${metrics.isHealthy}`);

Pool Information

import { getRedisPoolInfo } from '@/app/api/jobs/shared/redisClient';

const poolInfo = await getRedisPoolInfo();
console.log(`Connected clients: ${poolInfo.connectedClients}`);
console.log(`Memory used: ${poolInfo.usedMemory}`);

HTTP Monitoring

# Production health check
curl https://your-app.vercel.app/api/health/redis

# Check both Redis and database
curl https://your-app.vercel.app/api/health/redis
curl https://your-app.vercel.app/api/health/database

Files Created (4 files)

Implementation

  1. app/api/jobs/shared/redisClient.ts - Redis client manager with pooling
  2. app/api/health/redis/route.ts - Health check endpoint

Testing

  1. __tests__/api/jobs/redisClient.test.ts - Redis client tests
  2. __tests__/api/health-redis.test.ts - Health endpoint tests

Documentation

  1. docs/REDIS_SESSION_SHARING.md - Comprehensive guide

Other

  1. .changeset/852-redis-session-sharing.md - Changeset
  2. ISSUE_852_COMPLETION.md - This file

Files Modified (2 files)

  1. app/api/jobs/shared/jobRepository.ts - Updated to use Redis manager
  2. .env.example - Added Redis configuration variables
  3. app/api/jobs/shared/jobRepository.test.ts - Enhanced tests

Deployment Guides

Vercel Deployment

  1. Add Redis URL:

    vercel env add REDIS_URL production
  2. Enter connection string:

    rediss://:password@your-redis-host:6380
    
  3. Deploy:

    vercel deploy --prod
  4. Verify:

    curl https://your-app.vercel.app/api/health/redis

Recommended Redis Providers

Upstash (Best for Vercel):

  • Free tier available
  • Serverless-native
  • Global replication
  • Pay-per-request pricing
  • upstash.com

Redis Cloud:

  • Free 30MB tier
  • Managed service
  • Multiple clouds
  • redis.com

AWS ElastiCache:

Testing

Unit Tests

# Run all tests
npm test

# Run Redis-specific tests
npm test redisClient
npm test health-redis
npm test jobRepository

Integration Testing

  1. With Redis:

    # Start Redis
    docker run -p 6379:6379 redis:alpine
    
    # Set URL
    export REDIS_URL=redis://localhost:6379
    
    # Run tests
    npm test
  2. Without Redis (Fallback):

    # Unset URL
    unset REDIS_URL
    
    # Run tests (should use in-memory)
    npm test

Monitoring & Observability

Health Check Monitoring

// Set up periodic monitoring
setInterval(async () => {
  const response = await fetch('/api/health/redis');
  const data = await response.json();
  
  if (data.status !== 'healthy') {
    // Send alert
    console.error('Redis unhealthy:', data);
  }
}, 60000); // Check every minute

Metrics to Monitor

  1. Redis Availability

    • Status: connected/disconnected/reconnecting/error
    • Alert when status !== 'connected'
  2. Reconnection Attempts

    • Track reconnectAttempts in metrics
    • Alert when > 5 attempts
  3. Fallback Status

    • Monitor fallback.active in health endpoint
    • Alert when fallback is activated
  4. Pool Metrics

    • Connected clients count
    • Memory usage
    • Uptime

Production Alerts

// Example alert setup
async function checkRedisHealth() {
  const metrics = await getRedisHealthMetrics();
  
  // Alert on unhealthy
  if (!metrics.isHealthy) {
    sendAlert({
      level: 'critical',
      message: 'Redis is unhealthy',
      details: metrics,
    });
  }
  
  // Warn on high reconnection attempts
  if (metrics.reconnectAttempts > 5) {
    sendAlert({
      level: 'warning',
      message: 'High Redis reconnection attempts',
      details: metrics,
    });
  }
  
  // Warn on fallback
  if (!isRedisAvailable()) {
    sendAlert({
      level: 'warning',
      message: 'Using in-memory fallback',
      details: metrics,
    });
  }
}

Performance Benefits

  1. State Consistency: All serverless instances share the same state
  2. Connection Reuse: Connection pooling reduces overhead
  3. Automatic Recovery: Reconnection handles transient failures
  4. Graceful Degradation: Fallback prevents complete failure
  5. Optimized for Serverless: Configuration tuned for serverless environments

Troubleshooting

Redis Not Connecting

Check:

  • REDIS_URL format is correct
  • Redis server is running
  • Network connectivity
  • Firewall rules
  • TLS configuration (redis:// vs rediss://)

Solution:

# Test connection manually
redis-cli -u $REDIS_URL ping
# Should return: PONG

Fallback Active in Production

Check health endpoint:

curl https://your-app.vercel.app/api/health/redis

If Redis is down:

  • Check Redis provider status
  • Verify REDIS_URL in deployment
  • Review connection logs
  • Check for IP whitelist restrictions

High Reconnection Attempts

Symptoms:

  • metrics.reconnectAttempts > 5
  • Frequent connection/disconnection logs

Solutions:

  1. Increase connection timeout
  2. Check network stability
  3. Verify Redis server performance
  4. Consider Redis server closer to deployment

Best Practices

  1. Always Use TLS in Production

    REDIS_URL=rediss://...  # Note the 's'
  2. Set Strong Passwords

    • Use 32+ character random passwords
    • Rotate passwords periodically
  3. Monitor Health Continuously

    • Set up alerts for unhealthy status
    • Track reconnection attempts
    • Monitor fallback activation
  4. Test Failover

    • Simulate Redis downtime
    • Verify fallback works
    • Test reconnection
  5. Implement Cleanup

    • Add TTL to job keys
    • Periodic cleanup of old jobs
    • Monitor memory usage
  6. Use Appropriate Timeouts

    • Lower timeouts for faster failover
    • Higher timeouts for unstable networks
    • Test under production load

Success Metrics

All Acceptance Criteria MetProduction-Ready ImplementationComprehensive Test CoverageComplete DocumentationAutomatic FailoverHealth MonitoringConnection Pooling

Issue Status: COMPLETED ✅

All acceptance criteria have been implemented, tested, and documented. The Redis-based session sharing is production-ready with automatic failover, health monitoring, and comprehensive documentation.


Issue: #852 - Implement Redis-based session sharing across serverless instances
Status: ✅ COMPLETED
Date: 2024
Implementation: Full implementation with health checks, fallback, and connection pooling