ADR 009: Redis y requerimientos no funcionales¶
Estado¶
Aceptado — 2026-06 · Diseño de ingeniería (sin implementación aún)
Relacionado con ADR 001, ADR 007 y ADR 008 (idempotencia en POST).
Contexto¶
El marco técnico adopta prácticas NFR desde el desarrollo: rate limiting configurable por tenant, caché, health checks profundos e idempotencia en escrituras. Los umbrales numéricos (latencia, concurrencia, cuotas) se calibran en producción.
Hoy:
- Redis 7 está en
docker-compose.ymlyCORTEX_REDIS_URLen settings. RateLimitMiddlewarees un stub que deja pasar todas las peticiones./readydevuelve{"status": "ready"}sin comprobar dependencias.- No hay cliente Redis en código Python ni patrón de idempotencia.
Decisión¶
Rate limiting¶
- Implementar en
RateLimitMiddlewarecon Redis:INCR cortex:rl:{tenant}:{window}+ TTL 60s. - Límite por defecto:
CORTEX_RATE_LIMIT_PER_MINUTE(120); override por tenant en fase 2 (config en PG o Redis hash). - Respuesta
429con cuerpoApiError(RATE_LIMIT_EXCEEDED) y headerRetry-After. - Excluir:
/health,/ready,/api/docs,/api/openapi.json.
Caché (fase 2 — documentar, no bloquear fase 1)¶
- GET idempotentes de lectura: manifests UI, listados estáticos de recursos.
- Clave:
cortex:cache:{tenant}:{path_hash}; TTL corto (30–120s). - Invalidación en writes del mismo recurso.
Health checks¶
| Ruta | Comportamiento |
|---|---|
GET /api/v1/health | Liviano; proceso vivo |
GET /api/v1/ready | Comprueba Redis PING + PG SELECT 1 en tenant default |
Respuesta /ready si falla dependencia: 503 con detalle por servicio.
Idempotencia¶
- Header
Idempotency-KeyenPOST /api/v1/booking/bookings(y escrituras críticas futuras). - Redis:
cortex:idempotency:{tenant}:{key}→ respuesta serializada, TTL 24h. - Replay: misma respuesta HTTP sin re-ejecutar lógica.
Leyenda: Rate limit y health checks con Redis y PG (módulo Dependiente). Estado: Diseño (stub actual).
flowchart LR
API[FastAPI] --> RL[RateLimitMiddleware]
RL --> Redis[(Redis 7)]
API --> Ready["/ready"]
Ready --> Redis
Ready --> PG[(PostgreSQL)] Leyenda: Middleware y
/readydependen de Redis y PostgreSQL. Estado: Diseño.
sequenceDiagram
participant C as Cliente
participant API as FastAPI
participant Redis as Redis
participant DB as PostgreSQL
C->>API: POST /api/v1/booking/bookings Idempotency-Key
API->>Redis: GET idempotency key
alt clave existe
Redis-->>API: respuesta cacheada
API-->>C: 200 replay
else clave nueva
API->>DB: transacción crear
API->>Redis: SET idempotency TTL 24h
API-->>C: 201 created
end Leyenda: Idempotencia en POST booking vía Redis. Estado: Diseño.
Escalabilidad y stateless¶
- API sin sesión server-side; estado en PG y Redis.
- Réplicas horizontales detrás de Coolify/nginx sin sticky sessions.
- Pool de conexiones async SQLAlchemy por proceso (ADR 007).
Fuera de alcance documentado¶
- Umbrales numéricos de latencia/concurrencia (producción).
- Reintentos idempotentes en cliente (patrón recomendado en OpenAPI, no código framework).
- Rollback de despliegue (procedimiento ops Coolify).
Variables de entorno¶
| Variable | Default | Rol |
|---|---|---|
CORTEX_REDIS_URL | redis://localhost:6379/0 | Rate limit, idempotency, caché |
CORTEX_RATE_LIMIT_PER_MINUTE | 120 | Cuota por tenant por minuto |
Consecuencias¶
- Positivas: NFRs medibles, alineado con correo técnico, base para calibrar en producción.
- Negativas: Redis pasa a dependencia dura para rate limit;
/readymás lento pero útil para orquestadores.
Referencias¶
framework/cortex_framework/tenant/rate_limit.py— stub actualframework/cortex_framework/api/routes.py—/health,/ready- ADR 008 —
Idempotency-Key