Syntage · Entities sync (catálogo rfc ↔ entity_id)
Sincroniza el catálogo de entidades de Syntage (
GET /entities) a una tabla de mapeo en BigQuery, manteniendo frescoentity_id ↔ rfc ↔ credential.statuspara que otros procesos resuelvan elentityIda partir delrfc.
¿Llegaste hasta acá desde…?
| Si ves… | Eso sale de… | La lógica está en… |
|---|---|---|
Un mapeo rfc → entity_id o el credential_status de una entidad |
solvento-data-prod.syntage.entities |
Ingesta — Cloud Run syntage-entities-sync (repo) |
| "¿Corrió el sync de entidades hoy / hasta qué watermark?" | solvento-data-prod.syntage.entities_sync_control |
Tabla de control (watermark del incremental) |
Un proceso downstream que no encuentra el entity_id de un RFC nuevo |
solvento-data-prod.syntage.entities |
Falta correr el sync incremental; el catálogo es la dependencia |
| Campo | Valor |
|---|---|
| Origen | API Syntage GET /entities (paginación offset, itemsPerPage=1000) |
| Patrón | api-pull-programado (Cloud Run agendado por Cloud Scheduler) |
| Destino | solvento-data-prod.syntage.entities (+ entities_sync_control) |
| Frecuencia | Diaria 0 5 * * * (job syntage-entities-sync-daily, modo incremental, OIDC); full para backfill / re-sync completo |
| Criticidad | 🟡 Media (es dependencia de otros procesos) |
| Dueño | Martin |
| Repos | syntage-entities-sync |
Diagrama de linaje
graph LR
API[["🌐 API Syntage<br/>GET /entities"]]
SCH(["⏰ Cloud Scheduler<br/>syntage-entities-sync-daily<br/><i>0 5 * * * · incremental</i>"])
subgraph ing["Ingesta · Cloud Run programado"]
CR["syntage-entities-sync<br/><i>full | incremental · MERGE por entity_id</i>"]
ENT[("solvento-data-prod<br/>syntage.entities<br/>dimensión · upsert")]
CTRL[("syntage.entities_<br/>sync_control<br/>watermark")]
end
DOWN["Procesos downstream<br/><i>resuelven rfc → entity_id</i><br/>(p. ej. moratorios)"]
SCH --> CR
API --> CR
CR --> ENT
CR --> CTRL
ENT --> DOWN
classDef src fill:#fde68a,stroke:#b45309,color:#000;
classDef store fill:#bfdbfe,stroke:#1e40af,color:#000;
class API,SCH src;
class ENT,CTRL store;
Paso a paso
Ingesta — Cloud Run syntage-entities-sync (repo)
- Resuelve el modo.
incremental(default, corrida diaria): trae solo entidades conupdatedAtposterior al último sync exitoso, usando el filtroupdatedAt[after]de la API y aplicando un solapamiento (WATERMARK_OVERLAP_MINUTES, default 60m) para no perder registros de borde. El watermark sale delMAX(watermark)de las corridas constatus='success'enentities_sync_control.full: barre todas las entidades con paginación offset (~3 páginas para ~2.5k entidades), para la primera carga o un re-sync completo. - Consulta
GET /entitiescon paginación (ITEMS_PER_PAGE=1000) y manejo de rate limit (leeX-RateLimit-Remaining/X-RateLimit-Reset, pausa preventiva conRATE_LIMIT_MIN_REMAINING=5, backoff ante429conMAX_RETRIES=5). El sync es liviano, muy por debajo del límite de 60 req/min. - Escribe por MERGE (upsert) sobre
entity_idensyntage.entities(el catálogo es una dimensión, no un log: cada entidad existe una sola vez y se actualiza in-place;load_dtsse setea en cada upsert). Registra una fila por corrida ensyntage.entities_sync_control(sync_id,mode,watermark,entities_fetched,entities_upserted,started_at,finished_at,status).
Endpoints: POST /sync (body opcional {"mode":"full"|"incremental"}), POST / (alias de /sync para Scheduler simple), GET /health.
Orden recomendado: conviene correrlo antes del delta de intereses moratorios (Scheduler 0 5 * * *), para que una entidad nueva que facturó por primera vez hoy ya tenga su entity_id resuelto.
Tablas que alimenta
| Tabla | Contenido | Job que la carga |
|---|---|---|
solvento-data-prod.syntage.entities |
Catálogo entity_id ↔ rfc ↔ credential_status (+ tipo, nombre, fechas) |
Cloud Run syntage-entities-sync (MERGE) |
solvento-data-prod.syntage.entities_sync_control |
Una fila por corrida con el watermark del incremental | Cloud Run syntage-entities-sync |
Consumo aguas abajo
- Procesos de ingesta que necesitan el
entityIdde Syntage a partir delrfc(los webhooks de invoices traenrfc, pero los endpoints de insights se consultan porentityId). Ejemplo: el delta diario de intereses moratorios (syntage-moratory-interest).
Si falla 🛠️
Impacto: el catálogo entities queda desactualizado; los procesos downstream que dependen del mapeo rfc → entity_id no resolverán entidades nuevas. Criticidad media (no bloquea producto, pero es dependencia).
| Síntoma | Dónde mirar | Acción |
|---|---|---|
Una entidad/RFC nuevo no resuelve entity_id aguas abajo |
syntage.entities; entities_sync_control (¿corrió el incremental?) |
Re-invocar POST /sync {"mode":"incremental"} |
| El catálogo parece muy desfasado | entities_sync_control (watermark, status) |
Correr un POST /sync {"mode":"full"} para re-sincronizar todo |
| Errores 429 / rate limit | X-RateLimit-* en logs Cloud Run |
El servicio ya hace pausa/backoff; el sync es liviano, revisar si la API está degradada |
Escalación: Martin (Cloud Run de ingesta).
Enlaces
- 📦 Ingesta:
syntage-entities-sync - 📊 Estado en vivo: dashboard "Data Processes" (Cloud Monitoring)
Última actualización: 2026-06-21 · Si cambia el flujo, actualizar esta ficha en el mismo MR.