Successfully implemented Redis-based session sharing across serverless instances with connection pooling, health monitoring, and automatic fallback to in-memory storage.
Implementation:
- Redis client manager with singleton pattern
- Automatic detection of production environment
- Redis used by default when
REDIS_URLis configured - Logs warnings in production when Redis is not configured
Files:
app/api/jobs/shared/redisClient.ts- Redis client managerapp/api/jobs/shared/jobRepository.ts- Updated to use Redis manager
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 functionsapp/api/health/redis/route.ts- HTTP health endpoint
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 logicapp/api/jobs/shared/redisClient.ts- Availability checks
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
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
-
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
-
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
-
Health Check Endpoint (
app/api/health/redis/route.ts)- Real-time health status
- Pool metrics and statistics
- Fallback status indication
- Proper HTTP status codes
-
Comprehensive Testing
- Redis client manager tests
- Health endpoint tests
- Updated job repository tests
- Mock implementations for testing
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-
Connection Pooling
- Optimized for serverless environments
- Configurable pool parameters
- Keep-alive for persistent connections
- Offline command queueing
-
Health Monitoring
- Automatic health checks
- Detailed metrics tracking
- Real-time status updates
- HTTP monitoring endpoint
-
Automatic Reconnection
- Exponential backoff strategy
- Configurable max attempts
- Connection state tracking
- Graceful degradation
-
Fallback Mechanism
- Automatic detection of Redis unavailability
- Seamless fallback to in-memory storage
- No application code changes required
- Proper logging and warnings
-
Error Handling
- Comprehensive error logging
- Proper error propagation
- Recovery mechanisms
- User-friendly error messages
Development:
REDIS_URL=redis://localhost:6379Production (with TLS):
REDIS_URL=rediss://:password@your-redis-host:6380# 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# 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
}
}import { jobStore } from '@/app/api/jobs/shared/jobStore';
// Works with Redis OR in-memory storage automatically
const job = await jobStore.get('job-123');import { checkRedisHealth } from '@/app/api/jobs/shared/redisClient';
if (await checkRedisHealth()) {
console.log('Redis is healthy');
}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}`);import { getRedisPoolInfo } from '@/app/api/jobs/shared/redisClient';
const poolInfo = await getRedisPoolInfo();
console.log(`Connected clients: ${poolInfo.connectedClients}`);
console.log(`Memory used: ${poolInfo.usedMemory}`);# 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- ✅
app/api/jobs/shared/redisClient.ts- Redis client manager with pooling - ✅
app/api/health/redis/route.ts- Health check endpoint
- ✅
__tests__/api/jobs/redisClient.test.ts- Redis client tests - ✅
__tests__/api/health-redis.test.ts- Health endpoint tests
- ✅
docs/REDIS_SESSION_SHARING.md- Comprehensive guide
- ✅
.changeset/852-redis-session-sharing.md- Changeset - ✅
ISSUE_852_COMPLETION.md- This file
- ✅
app/api/jobs/shared/jobRepository.ts- Updated to use Redis manager - ✅
.env.example- Added Redis configuration variables - ✅
app/api/jobs/shared/jobRepository.test.ts- Enhanced tests
-
Add Redis URL:
vercel env add REDIS_URL production
-
Enter connection string:
rediss://:password@your-redis-host:6380 -
Deploy:
vercel deploy --prod
-
Verify:
curl https://your-app.vercel.app/api/health/redis
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:
- Enterprise-grade
- VPC integration
- Auto-scaling
- aws.amazon.com/elasticache
# Run all tests
npm test
# Run Redis-specific tests
npm test redisClient
npm test health-redis
npm test jobRepository-
With Redis:
# Start Redis docker run -p 6379:6379 redis:alpine # Set URL export REDIS_URL=redis://localhost:6379 # Run tests npm test
-
Without Redis (Fallback):
# Unset URL unset REDIS_URL # Run tests (should use in-memory) npm test
// 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-
Redis Availability
- Status: connected/disconnected/reconnecting/error
- Alert when status !== 'connected'
-
Reconnection Attempts
- Track reconnectAttempts in metrics
- Alert when > 5 attempts
-
Fallback Status
- Monitor fallback.active in health endpoint
- Alert when fallback is activated
-
Pool Metrics
- Connected clients count
- Memory usage
- Uptime
// 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,
});
}
}- State Consistency: All serverless instances share the same state
- Connection Reuse: Connection pooling reduces overhead
- Automatic Recovery: Reconnection handles transient failures
- Graceful Degradation: Fallback prevents complete failure
- Optimized for Serverless: Configuration tuned for serverless environments
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: PONGCheck health endpoint:
curl https://your-app.vercel.app/api/health/redisIf Redis is down:
- Check Redis provider status
- Verify REDIS_URL in deployment
- Review connection logs
- Check for IP whitelist restrictions
Symptoms:
- metrics.reconnectAttempts > 5
- Frequent connection/disconnection logs
Solutions:
- Increase connection timeout
- Check network stability
- Verify Redis server performance
- Consider Redis server closer to deployment
-
Always Use TLS in Production
REDIS_URL=rediss://... # Note the 's'
-
Set Strong Passwords
- Use 32+ character random passwords
- Rotate passwords periodically
-
Monitor Health Continuously
- Set up alerts for unhealthy status
- Track reconnection attempts
- Monitor fallback activation
-
Test Failover
- Simulate Redis downtime
- Verify fallback works
- Test reconnection
-
Implement Cleanup
- Add TTL to job keys
- Periodic cleanup of old jobs
- Monitor memory usage
-
Use Appropriate Timeouts
- Lower timeouts for faster failover
- Higher timeouts for unstable networks
- Test under production load
✅ All Acceptance Criteria Met ✅ Production-Ready Implementation ✅ Comprehensive Test Coverage ✅ Complete Documentation ✅ Automatic Failover ✅ Health Monitoring ✅ Connection Pooling
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