Integraciones B2B: cómo blindar el pipeline cuando el productor cambia el esquema sin avisar
Integraciones B2B: cómo blindar el pipeline cuando el productor cambia el esquema sin avisar
El correo llega a las 9:47 de la mañana. El pipeline lleva caído desde las 3:00. Nadie te avisó de que el campo source_url pasó a llamarse origin_link en la respuesta de la API. Un cambio menor, dicen. Para ti, cuatro horas de datos perdidos y un SLA en riesgo.
Este escenario no es una anécdota. Es la norma en integraciones B2B que no han formalizado el contrato de datos con el productor. Y la solución no es "hablar mejor con el proveedor": es diseñar el sistema para que ese cambio no rompa nada, aunque nadie te avise.
El problema de fondo: acoplar la lectura al esquema del productor
La mayoría de pipelines de integración leen la respuesta de una API y la mapean directamente a su modelo interno. Si el campo existe, lo usan. Si no existe, el proceso falla o —peor— sigue adelante con un valor nulo que contamina el análisis downstream.
Este diseño convierte cualquier cambio en el esquema del productor en un incidente. Y los cambios ocurren: campos renombrados, tipos que cambian de string a integer, arrays que aparecen donde antes había un objeto, fechas que migran de ISO 8601 a Unix timestamp. Ninguno de estos cambios es malicioso. La mayoría son legítimos. Todos rompen pipelines ingenuos.
El antídoto es desacoplar: nunca leer el esquema del productor directamente en la lógica de negocio. Siempre interponer una capa de traducción y validación.
Contratos de datos: qué son y por qué no basta con la documentación de la API
Un contrato de datos es un acuerdo explícito —técnico, no solo comercial— sobre qué campos existen, qué tipos tienen, qué valores son válidos y qué versión del esquema está activa. La documentación de la API no es un contrato. Es una intención. Los contratos se verifican en tiempo de ejecución.
La forma más pragmática de implementarlos es con un esquema de validación ejecutable: JSON Schema, Avro, Protobuf o incluso Pydantic en Python. El flujo es simple:
- La respuesta llega del proveedor.
- Se valida contra el esquema conocido antes de procesarla.
- Si la validación falla, el mensaje va a una cola de cuarentena, no al pipeline principal.
- Se genera una alerta que apunta al campo concreto que ha fallado.
Este patrón convierte los cambios de esquema en alertas silenciosas en lugar de incidentes silenciosos. La diferencia es crítica: en el primer caso, el equipo puede actuar. En el segundo, el problema se descubre cuando el informe del cliente tiene huecos inexplicables.
Estrategia defensiva: mapeo explícito con valores por defecto razonables
Validar el esquema no es suficiente si el pipeline colapsa ante cualquier campo opcional ausente. La estrategia defensiva combina validación con mapeo explícito.
def map_response(raw: dict) -> dict:
return {
"url": raw.get("source_url") or raw.get("origin_link") or "",
"published": parse_date(raw.get("published_at") or raw.get("pub_date")),
"sentiment": float(raw.get("sentiment_score", 0.0)),
"language": raw.get("lang", "und"), # "und" = undetermined
}
Este fragmento ilustra tres patrones defensivos en seis líneas:
- Aliases: busca el campo por su nombre antiguo y su nombre nuevo. Durante la transición, los dos nombres son válidos.
- Fallback a valor por defecto razonable: nunca un
Nonesilencioso que propague errores; un valor explícito que el análisis downstream puede manejar. - Normalización en el punto de entrada: la fecha se normaliza aquí, no en cinco sitios distintos del pipeline.
El coste de este mapeo explícito es menor que el coste de una hora de diagnóstico cuando algo falla.
Versionado del esquema: cómo gestionar migraciones sin cortar el flujo
Cuando el productor anuncia un cambio de versión —a veces con semanas de antelación, a veces con un changelog que nadie leyó— el pipeline necesita poder consumir ambas versiones simultáneamente durante el periodo de transición.
El patrón recomendado es la detección de versión en el mensaje:
def detect_schema_version(raw: dict) -> str:
if "origin_link" in raw and "schema_version" not in raw:
return "v2"
return raw.get("schema_version", "v1")
def process(raw: dict):
version = detect_schema_version(raw)
mapped = MAP_FUNCTIONS[version](raw)
ingest(mapped)
Este enfoque permite operar con múltiples versiones en producción sin flags de configuración globales. Cada mensaje lleva implícita o explícitamente su versión. El pipeline elige la función de mapeo adecuada. Cuando el productor retire la versión antigua, simplemente se elimina esa rama.
En integraciones con APIs de datos como las que expone FeedScale, donde el volumen de respuestas puede ser alto y la latencia de alerta es un requisito, este patrón evita que un cambio de esquema introduzca latencia adicional por reintentos o corrección manual.
Monitorización de la deriva del esquema en producción
Los cambios de esquema no siempre llegan anunciados. Algunos proveedores añaden campos nuevos opcionales sin notificación. Otros deprecan campos gradualmente, reduciendo su frecuencia de aparición antes de eliminarlos. Ambos comportamientos son invisibles si solo monitorizas errores de validación.
La solución es monitorizar la distribución de campos en el tiempo. Concretamente:
- Tasa de presencia de campo: porcentaje de respuestas en las que un campo concreto aparece. Una caída del 100 % al 60 % en
sentiment_scoreindica una deprecación silenciosa en curso. - Distribución de tipos: si un campo que siempre fue numérico empieza a devolver strings en el 5 % de los casos, hay una inconsistencia upstream que se convertirá en un error downstream.
- Cardinalidad de valores inesperados: si el campo
languageempieza a incluir valores fuera del catálogo conocido, el modelo de análisis puede estar recibiendo señales que no sabe interpretar.
Estos controles no requieren infraestructura compleja. Un job que agrega estadísticas sobre una ventana de una hora y las publica en un dashboard básico es suficiente para detectar derivas antes de que se conviertan en incidentes.
Lo que el pipeline no puede delegar al proveedor
La tentación en integraciones B2B es transferir la responsabilidad de la estabilidad al productor: "que nos avisen cuando cambien algo". Esa expectativa es razonable en un SLA bien negociado. No es suficiente como única línea de defensa.
Los proveedores tienen sus propios ciclos de release, sus propios incidentes, su propia deuda técnica. Un cambio de esquema no planificado es tan probable como cualquier otro tipo de fallo externo. El pipeline que sobrevive no es el que tiene el mejor SLA con el proveedor: es el que está diseñado para que los cambios externos sean eventos manejables, no incidentes críticos.
Validar en la entrada, mapear con aliases explícitos, versionar el esquema y monitorizar la deriva son cuatro decisiones de diseño. Cada una, por separado, reduce el radio de explosión de un cambio no anunciado. Las cuatro juntas convierten ese cambio en una alerta en el dashboard en lugar de una llamada de madrugada.