mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 19:19:41 +02:00
- Add uload project with apps/web structure
- Reorganize from flat to monorepo structure
- Remove PocketBase binary and local data
- Update to pnpm and @uload/web namespace
- Add picture project to monorepo
- Remove embedded git repository
- Unify all package names to @{project}/{app} schema:
- @maerchenzauber/* (was @storyteller/*)
- @manacore/* (was manacore-*, manacore)
- @manadeck/* (was web, backend, manadeck)
- @memoro/* (was memoro-web, landing, memoro)
- @picture/* (already unified)
- @uload/web
- Add convenient dev scripts for all apps:
- pnpm dev:{project}:web
- pnpm dev:{project}:landing
- pnpm dev:{project}:mobile
- pnpm dev:{project}:backend
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
7.3 KiB
7.3 KiB
Redis Cache Architecture
System Overview
uload uses Redis as a high-performance caching layer to accelerate link redirects and reduce database load.
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Browser │────▶│ SvelteKit │────▶│ Redis │
└─────────────┘ │ Server │ └─────────────┘
└─────────────┘ │
│ │ Cache Miss
│ ▼
│ ┌─────────────┐
└───────────▶│ PocketBase │
└─────────────┘
Cache Implementation
File Structure
src/lib/server/
├── redis.ts # Redis client configuration and helpers
└── linkCache.ts # Link-specific caching logic
src/routes/
├── [...slug]/
│ └── +page.server.ts # Link redirect with cache
└── api/
└── redis-status/
└── +server.ts # Redis health check endpoint
Core Components
1. Redis Client (redis.ts)
Provides a fault-tolerant Redis connection with automatic fallback:
// Connection detection
const REDIS_ENABLED = !!(
process.env.REDIS_HOST &&
(process.env.REDIS_PASSWORD || process.env.NODE_ENV === 'development')
);
// Graceful degradation
if (!redis || !redisAvailable) return null;
2. Link Cache (linkCache.ts)
Implements caching strategies for different link types:
class LinkCache {
// Fast redirect caching
async getRedirectUrl(shortCode: string): Promise<string | null>
async cacheRedirect(shortCode: string, targetUrl: string, popular: boolean)
// Full object caching
async cacheLink(link: Link): Promise<void>
async getLink(shortCode: string): Promise<Link | null>
// Cache management
async invalidate(shortCode: string): Promise<void>
async warmCache(links: Link[]): Promise<void>
}
Cache Strategy
TTL (Time To Live) Policy
| Content Type | TTL | Reason |
|---|---|---|
| Popular Links | 24 hours | Frequently accessed, rarely changed |
| Normal Links | 5 minutes | Balance between performance and freshness |
| User Link Lists | 5 minutes | May change frequently |
| Password-Protected | Never cached | Security requirement |
| Expired Links | Never cached | Would bypass expiration check |
Cache Key Patterns
redirect:{shortCode} # Direct URL for fast redirects
link:{shortCode} # Full link object with metadata
clicks:{shortCode} # Click counter
user:{userId}:links:page:{n} # Paginated user links
trending:links # Sorted set for analytics
test:ping # Health check key
Cache Warming
Popular links are pre-loaded into cache on startup:
async warmCache(links: Link[]): Promise<void> {
for (const link of links) {
await this.cacheRedirect(link.short_code, link.original_url, true);
}
}
Performance Optimization
1. Cache-First Strategy
// Check cache first (fastest path)
const cachedUrl = await linkCache.getRedirectUrl(shortCode);
if (cachedUrl) {
throw redirect(302, cachedUrl);
}
// Fall back to database
const link = await locals.pb.collection('links').getFirstListItem(...);
2. Async Cache Population
Cache writes are non-blocking to maintain low latency:
// Cache for next time (non-blocking)
if (link.is_active && !link.password) {
await linkCache.cacheRedirect(shortCode, link.original_url);
}
3. Trending Analytics
Click tracking without blocking redirects:
// Async increment hit counter (non-blocking)
this.incrementHitCount(shortCode).catch(console.error);
Fallback Mechanism
Graceful Degradation
The system continues functioning without Redis:
- Detection: Check Redis availability on startup
- Fallback: Skip cache operations if unavailable
- Recovery: Attempt reconnection periodically
- Logging: Track cache availability for monitoring
Error Handling
All cache operations are wrapped in try-catch blocks:
try {
await ensureRedisConnection();
// Cache operations...
} catch (error) {
console.error('Cache error:', error);
return null; // Continue without cache
}
Security Considerations
1. No Sensitive Data Caching
- Password-protected links bypass cache
- User authentication tokens never cached
- Personal data has minimal TTL
2. Cache Invalidation
Links are invalidated when:
- Link is updated
- Link is deleted
- Password protection added
- Expiration date reached
3. Rate Limiting
Redis enables efficient rate limiting:
const key = `rate:${ip}:${endpoint}`;
const count = await cache.incr(key);
if (count === 1) {
await cache.expire(key, 60); // 1 minute window
}
Monitoring & Debugging
Health Check Endpoint
GET /api/redis-status
{
"connected": true,
"host": "localhost",
"enabled": true,
"available": true,
"cachedLinks": 42,
"error": null
}
Console Logging
Development mode provides detailed logs:
✅ Redis: Connected successfully
Cache HIT! Redirecting from cache
Cache MISS - fetching from PocketBase
Cached redirect for future use
Performance Metrics
Track cache effectiveness:
// Hit rate calculation
const hits = await redis.get('stats:cache:hits') || 0;
const misses = await redis.get('stats:cache:misses') || 0;
const hitRate = hits / (hits + misses) * 100;
Production Considerations
1. Memory Management
# Set max memory in Redis config
maxmemory 256mb
maxmemory-policy allkeys-lru
2. Persistence Options
# Disable persistence for cache-only use
save ""
appendonly no
3. Connection Pooling
const redisConfig = {
retryDelayOnFailover: 100,
maxRetriesPerRequest: 3,
enableOfflineQueue: false,
lazyConnect: true
};
4. Monitoring Setup
- Use Redis INFO command for metrics
- Set up alerts for connection failures
- Monitor memory usage and eviction rate
- Track cache hit/miss ratio
Scaling Strategies
Horizontal Scaling
- Redis Cluster: Distribute cache across nodes
- Read Replicas: Separate read/write operations
- Sharding: Partition by link patterns
Vertical Scaling
- Memory: Increase Redis memory allocation
- CPU: Optimize for single-threaded performance
- Network: Reduce latency with proximity
Future Enhancements
Planned Improvements
- Smart Preloading: ML-based prediction of popular links
- Geolocation Caching: CDN-style distributed cache
- Real-time Analytics: Stream processing with Redis Streams
- Cache Warming API: Admin endpoint for cache management
- A/B Testing: Cache different versions for experiments
Performance Goals
| Metric | Current | Target |
|---|---|---|
| Cache Hit Rate | 70% | 90% |
| Redirect Latency | 20ms | 10ms |
| Memory Usage | 100MB | 50MB |
| TTL Optimization | Static | Dynamic |