Métricas — Arquitectura¶
Una sola función Lambda ApiLambdaMetricasEntregaCiudad (.NET 10, no AOT, Clean Architecture) con dos puertas que distingue por el evento que recibe:
- Evento de corrida
{ "tipo": "CORRIDA", ... }(lo manda el EventBridge Scheduler o la autoinvocación asíncrona de una corrida manual): ejecuta el cálculo y escribe el resumen.DetectorEventoCorridareconoce la propiedadtiposin distinguir mayúsculas: el Scheduler mandatipoy la autoinvocación serializaTipo. - Evento de API Gateway (trae
httpMethod): enruta a los casos de uso de lectura y administración.
Capas (Clean Architecture)¶
| Capa | Qué contiene | Toca Mongo/AWS |
|---|---|---|
Dominio |
Reglas puras: ClasificadorEstado, NormalizadorTransportadora, ResolutorCiudad, CalculadoraPorcentaje, CalculadoraAlcance, AcumuladorResumen, PoliticaCandado, ValidadorConfiguracion, ExtractorMes, CatalogoCiudades, NormalizadorTexto |
No |
Aplicacion |
Casos de uso (EjecutarCorrida, ConsultarResumen, LanzarCorridaManual, GuardarConfiguracion…), EnrutadorApi, DetectorEventoCorrida, DTOs, puertos (IVerificadorToken…), AutorizacionUsuario |
No (puertos) |
Infraestructura |
Repositorios Mongo, InvocadorCorridaLambda, VerificadorJwtCognito, EncripcionAES, RelojBogota |
Sí |
209 tests en verde (2026-10-30). El dominio y los casos de uso están cubiertos por tests; la infraestructura de Mongo se prueba contra Atlas, no con tests unitarios. El verificador de JWT sí tiene tests unitarios (genera sus propias claves RSA y un JWKS falso; sin red).
Flujo de una corrida¶
flowchart TD
S[EventBridge Scheduler
domingo 8:00 Bogotá] -->|evento CORRIDA PROGRAMADA| L
F[Front / admin] -->|POST /corridas alcance| G[API Gateway]
G --> L[ApiLambdaMetricasEntregaCiudad]
L -->|valida rol, toma candado,
crea corrida EN_CURSO, autoinvoca| L
L -->|202 corridaId| F
L -->|1 agregación por mes/ciudad/depto/
transportadora/estado/fechas| P[(PedidosInter
secondaryPreferred)]
L -->|lee| C[(Ciudades + Configuración)]
L -->|upsert por mes + borra obsoletos| R[(MetricasEntregaCiudadMes)]
L -->|FINALIZADA/FALLIDA + auditoría| K[(MetricasEntregaCorridas)]
V[Front, cualquier rol] -->|GET /entrega-ciudad desde/hasta| G
G --> L -->|suma meses| R
Pasos¶
- Candado (RN-08):
findOneAndUpdateatómico sobre el documento de candado. Si hay una corridaEN_CURSOde menos de 20 min, la nueva se rechaza (manual → 409; programada →OMITIDA); una de más de 20 min se considera caída y se libera. La corrida manual toma el candado al lanzarse y su autoinvocación lo vuelve a tomar con el mismoCorridaId: el filtro del repositorio acepta esa re-toma (idempotente); con el candado de otra corrida se omite. - Leer configuración (
_id="entrega-ciudad") y catálogoCiudadesa memoria. - Una agregación sobre
PedidosInter(secondaryPreferred,allowDiskUse,maxTimeMS):$matchpor rango deFechaCarga+$grouppor mes, ciudad, departamento, transportadora, estado y presencia de fechas. Solo operadores ya probados en DocumentDB ($match,$group,$substr,$cond,$ne,$ifNull). - Calcular en memoria: normalizar transportadora y ciudad, clasificar cada grupo, acumular por
(mes, mun8, transportadora)y armar la auditoría. - Escribir el resumen:
bulkWritecon upsert por_id = "<mes>|<mun8>|<transportadora>"con elCorridaId; luego borrar los documentos de los meses del alcance conCorridaIddistinto (combinaciones que desaparecieron). Sin transacciones (DocumentDB). - Cerrar la corrida (
FINALIZADAcon métricas oFALLIDAcon error) y liberar el candado.
Colecciones (base LogighoDB)¶
| Colección | Rol | Escribe |
|---|---|---|
PedidosInter |
Fuente de verdad (se lee, nunca se escribe) | — |
Ciudades |
Catálogo DANE para resolver mun8 (se lee) |
— |
Users |
Roles por sub para autorizar (se lee) |
— |
MetricasEntregaCiudadMes |
Resumen: un doc por (mes, mun8, transportadora) |
La corrida |
MetricasEntregaCorridas |
Auditoría de cada corrida | La corrida |
MetricasEntregaConfiguracion |
Config editable (_id="entrega-ciudad") + candado (_id="candado-entrega-ciudad") |
PUT config / corrida |
Variables de entorno (solo nombres)¶
| Variable | Para qué |
|---|---|
CADENA_CONEXION |
Cadena Mongo cifrada AES (se descifra con Seguridad.Encripcion); secreto en Azure Library |
DATABASE_NAME |
Base de datos (LogighoDB) |
COLECCION_PEDIDOS |
Colección que se agrega en cada corrida (PedidosInter) |
COLECCION_USUARIOS |
Colección de roles por sub (Users) |
NOMBRE_FUNCION |
Nombre con el que la función se autoinvoca en la corrida manual; sin ella falla al construirse |
MAX_TIME_AGREGACION_SEG |
maxTimeMS de la agregación (por defecto 600) |
COGNITO_REGION, COGNITO_USER_POOL_ID, COGNITO_CLIENT_IDS |
Verificación de la firma del JWT. Si falta cualquiera, la lambda rechaza todos los tokens (falla cerrado) |
Se cargan por Azure Library de forma aditiva (el CD nunca pisa un valor ya puesto en la función); los valores nunca van en el repo ni en el YAML. Terraform pone solo DATABASE_NAME, COLECCION_PEDIDOS y NOMBRE_FUNCION al crear la función.
Tamaño y tiempos (producción, 2026-10-30)¶
Función con 1024 MB y timeout de 900 s, dentro de la VPC de prod. La primera corrida TODO sobre 926 476 guías duró 1 min 53 s y escribió 25 023 documentos.