# Optimizaciones de Rendimiento - ServiceManagerWeb ## 🎯 Estado Actual El sistema funciona correctamente, pero podemos implementar mejoras para hacerlo más rápido. ## 🚀 Optimizaciones Implementables ### 1. **Backend - Base de Datos** (ALTO IMPACTO) #### A. Aumentar Pool de Conexiones **Archivo**: `backend/app/core/database.py` ```python # Actual engine = create_async_engine( settings.DATABASE_URL, pool_size=5, # ← Aumentar a 20 max_overflow=10, # ← Aumentar a 30 pool_pre_ping=True, ) # Optimizado engine = create_async_engine( settings.DATABASE_URL, pool_size=20, # Más conexiones concurrentes max_overflow=30, # Más overflow para picos pool_pre_ping=True, pool_recycle=3600, ) ``` **Impacto**: ⚡ 30-50% más rápido en endpoints con DB --- #### B. Agregar Índices Faltantes **Ejecutar migrations**: ```sql -- Índices para queries frecuentes CREATE INDEX CONCURRENTLY idx_tickets_status_tenant ON tickets(status, tenant_id); CREATE INDEX CONCURRENTLY idx_tickets_assigned_to ON tickets(assigned_to); CREATE INDEX CONCURRENTLY idx_tickets_created_at ON tickets(created_at DESC); CREATE INDEX CONCURRENTLY idx_users_email_tenant ON users(email, tenant_id); CREATE INDEX CONCURRENTLY idx_audit_logs_tenant_created ON audit_logs(tenant_id, created_at DESC); ``` **Impacto**: ⚡ 40-70% más rápido en listados y búsquedas --- ### 2. **Backend - Caché con Redis** (ALTO IMPACTO) #### Crear servicio de caché **Nuevo archivo**: `backend/app/core/cache.py` ```python """Redis caching service""" from redis import asyncio as aioredis from typing import Optional, Any import json from app.core.config import get_settings settings = get_settings() class CacheService: def __init__(self): self.redis = None async def connect(self): self.redis = await aioredis.from_url( settings.REDIS_URL, encoding="utf-8", decode_responses=True ) async def get(self, key: str) -> Optional[Any]: if not self.redis: await self.connect() value = await self.redis.get(key) return json.loads(value) if value else None async def set(self, key: str, value: Any, ttl: int = 300): if not self.redis: await self.connect() await self.redis.setex(key, ttl, json.dumps(value)) async def delete(self, key: str): if not self.redis: await self.connect() await self.redis.delete(key) cache = CacheService() ``` #### Usar en endpoints frecuentes: ```python # Ejemplo: Cachear listado de categorías @router.get("/categories") async def list_categories(db: AsyncSession = Depends(get_db)): cache_key = f"categories:tenant:{tenant_id}" # Intentar cache cached = await cache.get(cache_key) if cached: return cached # Si no hay cache, query DB result = await db.execute(select(Category)) categories = result.scalars().all() # Guardar en cache por 5 minutos await cache.set(cache_key, categories, ttl=300) return categories ``` **Impacto**: ⚡ 80-95% más rápido en datos que no cambian frecuentemente --- ### 3. **Backend - Uvicorn Workers** (MEDIO IMPACTO) #### Actualizar Dockerfile **Archivo**: `docker/Dockerfile.backend` ```dockerfile # Cambiar la última línea de: CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] # A modo producción: CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"] ``` **Nota**: Quitar `--reload` en producción (consume recursos). **Impacto**: ⚡ 2-4x más throughput (requests por segundo) --- ### 4. **Frontend - Code Splitting y Lazy Loading** (MEDIO IMPACTO) #### Configurar lazy loading en rutas **Archivo**: `frontend-internal/src/routes/+layout.svelte` ```typescript // En lugar de importar todo: import HeavyComponent from '$lib/components/HeavyComponent.svelte'; // Usar dynamic imports: const HeavyComponent = () => import('$lib/components/HeavyComponent.svelte'); ``` #### Optimizar build de Vite **Archivo**: `frontend-internal/vite.config.js` ```javascript export default { build: { rollupOptions: { output: { manualChunks: { 'vendor': ['svelte', 'svelte/store'], 'charts': ['chart.js'], // Si usas charts } } } } } ``` **Impacto**: ⚡ 40-60% más rápido el load inicial del frontend --- ### 5. **Queries SQL - Eager Loading** (ALTO IMPACTO) #### Usar selectinload para relaciones **Ejemplo en endpoints de tickets**: ```python # Antes (N+1 queries) query = select(Ticket).where(Ticket.tenant_id == tenant_id) # Después (1 query con joins) query = select(Ticket).options( selectinload(Ticket.category), selectinload(Ticket.assigned_user), selectinload(Ticket.comments) ).where(Ticket.tenant_id == tenant_id) ``` **Impacto**: ⚡ 50-80% más rápido al traer relaciones --- ### 6. **Logging en Producción** (MEDIO IMPACTO) #### Reducir logging en producción **Archivo**: `.env` ```bash # Development DEBUG=true LOG_LEVEL=INFO # Production (cambiar a) DEBUG=false LOG_LEVEL=WARNING ``` **Impacto**: ⚡ 10-15% menos overhead --- ### 7. **Docker - Recursos** (BAJO IMPACTO) #### Asignar más recursos en docker-compose **Archivo**: `docker-compose.yml` ```yaml backend: # ... config existente deploy: resources: limits: cpus: '2.0' memory: 2G reservations: cpus: '1.0' memory: 512M postgres: # ... config existente deploy: resources: limits: cpus: '2.0' memory: 2G ``` --- ## 📊 Prioridades de Implementación ### **Fase 1 - Quick Wins** (1-2 horas) 1. ✅ Aumentar pool de DB 2. ✅ Quitar `--reload` en producción 3. ✅ Reducir logging (LOG_LEVEL=WARNING) **Ganancia esperada**: 30-40% mejora general --- ### **Fase 2 - Optimizaciones Importantes** (2-4 horas) 1. ✅ Agregar índices de DB 2. ✅ Implementar caché con Redis 3. ✅ Eager loading en queries complejas **Ganancia esperada**: 50-70% mejora en endpoints cacheables --- ### **Fase 3 - Optimizaciones Avanzadas** (4-8 horas) 1. ✅ Uvicorn workers múltiples 2. ✅ Frontend code splitting 3. ✅ Optimización de queries lentas **Ganancia esperada**: 2-3x mejora en throughput total --- ## 🔧 Comandos Rápidos ### Implementar Fase 1 (copiar y ejecutar): ```bash # 1. Editar database.py (aumentar pools) # Ver sección 1.A arriba # 2. Editar Dockerfile.backend (quitar reload) # Ver sección 3 arriba # 3. Editar .env echo "DEBUG=false" >> .env echo "LOG_LEVEL=WARNING" >> .env # 4. Reiniciar servicios docker-compose restart backend ``` --- ## 📈 Monitorear Mejoras ```bash # Medir tiempo de respuesta ANTES curl -w "@-" -o /dev/null -s http://localhost:8000/v1/tickets <<'EOF' time_total: %{time_total}s\n EOF # Implementar optimizaciones... # Medir tiempo de respuesta DESPUÉS curl -w "@-" -o /dev/null -s http://localhost:8000/v1/tickets <<'EOF' time_total: %{time_total}s\n EOF ``` --- ## ⚡ Resultados Esperados | Métrica | Actual | Optimizado | Mejora | |---------|--------|------------|--------| | Login | ~300ms | ~100ms | 3x | | Listar tickets | ~500ms | ~150ms | 3.3x | | Crear ticket | ~400ms | ~200ms | 2x | | Dashboard SLA | ~800ms | ~200ms | 4x (con cache) | | Load frontend | ~2s | ~800ms | 2.5x | --- ## 🎓 Mejores Prácticas Adicionales 1. **Paginación siempre**: Nunca devolver listados sin límite 2. **Índices compuestos**: Para queries con múltiples WHERE 3. **Redis para sesiones**: Mover JWT refresh tokens a Redis 4. **CDN para assets**: Servir JS/CSS desde CDN en producción 5. **HTTP/2**: Configurar Nginx con HTTP/2 --- ## 📝 Notas Importantes - **Redis ya está corriendo**: Solo falta implementar CacheService - **No optimizar prematuramente**: Medir primero, optimizar después - **Testing**: Probar cada optimización para evitar regresiones - **Monitoring**: Agregar métricas con Prometheus/Grafana (opcional) --- ¿Quieres que implemente alguna de estas optimizaciones ahora?