perf: Comprehensive efficiency optimizations
Implemented all 5 critical efficiency improvements to optimize performance, reduce resource usage, and improve scalability. ## 1. Database Indexes - Added indexes on sermon_notes foreign keys (user_id, sermon_id) - Added composite index on sermons (archived, date DESC) - Added indexes on frequently queried columns across all tables - Impact: Faster queries as data grows, better JOIN performance ## 2. Eliminated N+1 Query Pattern - Reduced 2 API calls to 1 on home page load - Changed from separate active/archived fetches to single call - Filter archived sermons client-side using computed properties - Impact: 50% reduction in HTTP requests per page load ## 3. Scheduled Database Cleanup - Extended existing plugin to clean expired sessions hourly - Added cleanup for expired rate limits every hour - Added cleanup for expired password reset codes every hour - Sermon cleanup continues to run daily based on retention policy - Impact: Prevents database table growth, better performance ## 4. Multi-stage Docker Build - Implemented 3-stage build: deps -> builder -> runtime - Separated build-time and runtime dependencies - Added non-root user (nuxt:nodejs) for security - Integrated dumb-init for proper signal handling - Added health check endpoint at /api/health - Impact: Smaller image size, faster deployments, better security ## 5. HTTP Caching - Static assets: 1 year cache (immutable) - Logos/images: 1 year cache (immutable) - API routes: No cache (always fresh) - HTML pages: 10 minute cache with revalidation - Impact: Reduced bandwidth, faster page loads, less server load All optimizations follow best practices and maintain backward compatibility with existing functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { getSetting, deleteOldSermons } from '../utils/database'
|
||||
import { getSetting, deleteOldSermons, deleteExpiredSessions, getDatabase } from '../utils/database'
|
||||
|
||||
// Map retention policy to days
|
||||
const retentionDaysMap: Record<string, number> = {
|
||||
@@ -12,7 +12,7 @@ const retentionDaysMap: Record<string, number> = {
|
||||
'10_years': 3650
|
||||
}
|
||||
|
||||
async function runCleanup() {
|
||||
async function runSermonCleanup() {
|
||||
try {
|
||||
// Get the retention policy setting
|
||||
const setting = getSetting('sermon_retention_policy')
|
||||
@@ -34,23 +34,76 @@ async function runCleanup() {
|
||||
console.log(`[Sermon Cleanup] No sermons to delete (policy: ${retentionPolicy})`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Sermon Cleanup] Error running cleanup:', error)
|
||||
console.error('[Sermon Cleanup] Error running sermon cleanup:', error)
|
||||
}
|
||||
}
|
||||
|
||||
export default defineNitroPlugin((nitroApp) => {
|
||||
console.log('[Sermon Cleanup] Scheduling daily cleanup task')
|
||||
async function runSessionCleanup() {
|
||||
try {
|
||||
const result = deleteExpiredSessions()
|
||||
if (result.changes > 0) {
|
||||
console.log(`[Session Cleanup] Deleted ${result.changes} expired session(s)`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Session Cleanup] Error cleaning expired sessions:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Run cleanup once at startup (after a short delay)
|
||||
async function runRateLimitCleanup() {
|
||||
try {
|
||||
const db = getDatabase()
|
||||
const result = db.prepare("DELETE FROM rate_limits WHERE reset_at <= datetime('now')").run()
|
||||
if (result.changes > 0) {
|
||||
console.log(`[Rate Limit Cleanup] Deleted ${result.changes} expired rate limit(s)`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Rate Limit Cleanup] Error cleaning expired rate limits:', error)
|
||||
}
|
||||
}
|
||||
|
||||
async function runPasswordResetCleanup() {
|
||||
try {
|
||||
const db = getDatabase()
|
||||
const result = db.prepare("DELETE FROM password_reset_codes WHERE expires_at <= datetime('now')").run()
|
||||
if (result.changes > 0) {
|
||||
console.log(`[Password Reset Cleanup] Deleted ${result.changes} expired reset code(s)`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Password Reset Cleanup] Error cleaning expired password reset codes:', error)
|
||||
}
|
||||
}
|
||||
|
||||
async function runAllCleanupTasks() {
|
||||
console.log('[Cleanup] Starting scheduled cleanup tasks')
|
||||
await runSermonCleanup()
|
||||
await runSessionCleanup()
|
||||
await runRateLimitCleanup()
|
||||
await runPasswordResetCleanup()
|
||||
console.log('[Cleanup] All cleanup tasks completed')
|
||||
}
|
||||
|
||||
export default defineNitroPlugin((nitroApp) => {
|
||||
console.log('[Cleanup Plugin] Initializing scheduled cleanup tasks')
|
||||
|
||||
// Run all cleanup tasks at startup (after a short delay)
|
||||
setTimeout(async () => {
|
||||
console.log('[Sermon Cleanup] Running initial cleanup')
|
||||
await runCleanup()
|
||||
console.log('[Cleanup] Running initial cleanup')
|
||||
await runAllCleanupTasks()
|
||||
}, 10000) // 10 seconds after startup
|
||||
|
||||
// Schedule cleanup to run daily (every 24 hours)
|
||||
// Schedule cleanup to run daily (every 24 hours) for sermons
|
||||
const dailyInterval = 24 * 60 * 60 * 1000 // 24 hours in milliseconds
|
||||
setInterval(async () => {
|
||||
console.log('[Sermon Cleanup] Running scheduled cleanup')
|
||||
await runCleanup()
|
||||
await runAllCleanupTasks()
|
||||
}, dailyInterval)
|
||||
|
||||
// Run session/rate-limit cleanup more frequently (every hour)
|
||||
// This prevents these tables from growing too large
|
||||
const hourlyInterval = 60 * 60 * 1000 // 1 hour in milliseconds
|
||||
setInterval(async () => {
|
||||
console.log('[Cleanup] Running hourly cleanup')
|
||||
await runSessionCleanup()
|
||||
await runRateLimitCleanup()
|
||||
await runPasswordResetCleanup()
|
||||
}, hourlyInterval)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user