Skip to main content

Gotchas de ingesta: las fallas silenciosas al frente del pipeline

Las fallas de ingesta que no lanzan un error. Un upsert conserva registros borrados en el origen porque nada le avisó que se fueron; un full refresh sobre un origen enorme factura como una decisión de costo que nadie tomó; una clave no única sobrescribe un registro; una cadencia diaria queda detrás de una decisión en tiempo real; datos de evento aterrizan como stream Profile y la serie temporal nunca existe; un DLO se infla porque nadie reconcilia lo que ingiere contra lo que usa; un conector pierde la autenticación en silencio y parece un origen sin datos. Siete gotchas, cada uno como el instinto, lo que pasa de verdad en producción, y el arreglo.

Nota de producción·Actualizado 2026-06-01·Escrito por Lira · Editado por German Medina

La ingesta es la demo fácil y el sistema de producción difícil. En un sandbox con un origen limpio y unos pocos miles de filas, un Data Stream parece un checkbox: apuntalo a un origen, elegí una agenda, mirá aterrizar las filas, seguí. El costo aparece después, a escala, sobre datos reales que cambian y se borran y llegan tarde — y casi nunca como un error. La ingesta falla en silencio. El stream corre en verde, el conteo de filas parece plausible, el timestamp de la última corrida es reciente, y la falla es un cliente borrado al que se le sigue enviando mail, un conteo que cuenta doble, o un incidente de "faltan datos" que en realidad es una credencial vencida hace tres semanas.

Siete elecciones de ingesta que mordieron las builds de Data 360 (antes Data Cloud) de Cleon, sintetizadas con la guía oficial de Salesforce y las correcciones que la comunidad de practicantes aprendió a los golpes. Cada una va con el instinto que te mete adentro, lo que pasa de verdad en producción, y el arreglo. El hilo conductor es el que esta subcategoría repite: la ingesta es el frente del ciclo de vida, y todo lo de abajo hereda lo que aterrizaste — así que un error silencioso de ingesta aparece como un bug de identidad, segmento o activación tres capas más allá, mucho después de que el stream que lo causó dejó de parecer sospechoso.


Los gotchas

1. Elegir upsert por eficiencia — conserva los registros borrados en el origen para siempre, porque nada le avisó que se fueron

El instinto acierta en el costo y se equivoca en la completitud: el origen es grande, un full refresh mueve todo el conjunto en cada corrida, así que elegís upsert para aterrizar solo el delta. Funciona exactamente como se promociona para inserts y updates — cada corrida lleva lo que cambió, el DLO queda al día, la factura de procesamiento baja. Lo que no hace es notar un registro que se fue del origen, porque el upsert solo toca un registro que está presente en la corrida, y un registro borrado es justamente el que deja de llegar.

Lo que pasa de verdad en producción es un DLO que acumula fantasmas. Un cliente borrado del CRM, un producto retirado del catálogo, un contacto que ejerció un pedido de borrado — ninguno desaparece solo de un DLO alimentado por upsert. Quedan ahí, indistinguibles de los registros vivos, y fluyen hacia abajo hacia resolución de identidad, segmentos y activaciones. La primera señal suele ser humana: alguien recibe contacto cuando debió ser removido, o un conteo incluye personas que el origen ya no tiene. Nada dio error; la corrida fue verde; el dato está mal.

2. Poner un origen enorme en un full refresh frecuente — es una decisión de costo disfrazada de configuración de agenda

El instinto es ir al full refresh porque es el modo más simple de razonar — sin clave que acertar, deletes manejados por ausencia — y después poner la cadencia alta porque "más fresco es mejor". Las dos mitades se sienten como la elección segura y prolija. Sobre un origen chico lo son. Sobre uno grande, la combinación se vuelve en silencio el ítem más caro de la build, y nadie lo decidió a propósito.

Lo que pasa de verdad es que cada corrida vuelve a aterrizar y a procesar el conjunto entero, aun cuando cambió una fila, y Data 360 factura por el trabajo que procesa, no por el dato en reposo (principio 11). Un origen de varios millones de filas en un full refresh por hora mueve todas esas filas cada hora, todo el día, haya cambiado algo o no. El campo de agenda parece inocente — es un dropdown al lado del stream — pero es una decisión de throughput, y un full refresh demasiado frecuente sobre un origen grande es una decisión de costo disfrazada de configuración de agenda. La factura es de las que se descubren en una revisión de uso, no en una corrida verde.

El arreglo es dimensionar la cadencia según la decisión más fresca que los datos realmente alimentan, y después pesar el modo contra el volumen. Si la decisión de abajo es un batch nocturno, un refresco por hora no compra nada y cuesta cada hora. Si el origen es grande y mayormente append/update con una clave estable, el upsert mueve solo el delta y es el mecanismo más barato — siempre que hayas resuelto la cuestión de los deletes (gotcha 1). Escribí la cadencia al lado del stream junto con la decisión a la que sirve, para que el próximo no herede un default caro que nadie eligió (principios 6 + 11; el Style Guide lo plantea como su tercera pregunta).

3. Usar como clave de un upsert un campo que no es realmente único — sobrescribe o duplica en silencio, y la corrida igual va en verde

El instinto es elegir una clave primaria que parece suficientemente única — un email, nombre-más-código-postal, un ID externo que asumís estable — y confiar en que el upsert reconcilie sobre ella. El editor la acepta, la primera corrida aterriza, el conteo parece bien. La clave es todo el contrato sobre el que corre el upsert, y una clave que es casi única falla de la peor manera: no a los gritos, sino corrompiendo en silencio el conjunto que debía mantener limpio.

Lo que pasa de verdad se parte en dos, ambos invisibles. Una clave no única — dos registros genuinamente distintos comparten el valor — significa que el stream no puede diferenciarlos, así que un upsert sobrescribe al otro y un registro real desaparece sin error. Una clave equivocada — usaste como clave un campo que en realidad no es estable, así que el mismo registro llega pareciendo nuevo en cada corrida — significa que el registro se duplica en cada corrida, y el DLO se infla con copias que la plataforma cree distintas. Las dos se presentan como una corrida verde y sana. El daño aparece abajo como un conteo que no cuadra o un perfil al que le faltan datos que debería tener, y la causa es el grano, no el dato.

El arreglo es tratar la clave como un prerrequisito que verificás, no un campo que completás. Nombrá la clave antes de elegir upsert — principio 1, modelá las claves, aplicado en la ingesta — y confirmá contra datos reales que sea genuinamente única (que no haya dos registros distintos que la compartan) y genuinamente estable (que el mismo registro lleve el mismo valor corrida tras corrida). Si no podés nombrar semejante clave, no estás listo para upsert; usá full refresh hasta que lo estés (modos de refresco, relaciones y claves).

4. Poner la cadencia por "más fresco es mejor" — un refresco diario detrás de una decisión en tiempo real es un bug de latencia

El instinto trata la frescura como un único dial donde más alto siempre es mejor, así que la cadencia se pone por costumbre o por la conveniencia del origen y no por lo que consume el dato. A veces eso significa demasiado frecuente (el problema de costo del gotcha 2); con la misma frecuencia significa demasiado lento para lo que el dato alimenta — un refresco diario o dos veces al día sentado bajo una decisión que necesita señal casi en tiempo real. Parece bien porque el stream está verde y el dato es real; solo que es viejo.

Lo que pasa de verdad es un bug de latencia que ningún error reporta. Un stream que refresca a diario detrás de una activación en tiempo real significa que la activación dispara sobre el estado de ayer — un cliente que convirtió esta mañana sigue en el segmento de "no convirtió" esta noche, y recibe el empujón que ya no necesita. Una señal de carrito abandonado que aterriza en un batch nocturno llega un día después de que el carrito se enfrió. La brecha de frescura es invisible en todo dashboard, porque el dashboard muestra el dato que está ahí, no las horas de obsolescencia delante de él. La frescura es una feature (principio 6), y una feature ausente acá es silenciosa por construcción.

El arreglo es poner la cadencia desde la decisión de abajo, no desde el origen. Encontrá la decisión más fresca que el dato alimenta y hacé que la ingesta la cumpla — streaming (el patrón Streaming de la Ingestion API o el SDK Web/Mobile) para tiempo real genuino, batch agendado para todo lo que una agenda sirve. Después escribí la cadencia y la decisión a la que sirve al lado del stream, para que nadie abajo asuma tiempo real donde hay un retraso de 24 horas, y nadie arriba transmita por streaming lo que un batch nocturno habría servido (principios 6 + 11; conectores cubre qué orígenes son batch y cuáles streaming).

5. Aterrizar datos de evento como un stream Profile — ingiere limpio, y la serie temporal nunca existe

El instinto es que un dato sobre el comportamiento de un cliente sigue siendo un dato sobre el cliente, así que un stream de compras o eventos web se crea como un stream Profile — la misma categoría que el registro de cliente con el que se relaciona. Ingiere sin quejarse. Las filas aterrizan en un DLO, el conteo está bien, nada marca la elección. La categoría no es cosmética, sin embargo: le dice a Data 360 cómo se comporta el dato y restringe lo que podés hacer con él aguas abajo, y Profile y Engagement no son intercambiables.

Lo que pasa de verdad es que la serie temporal que necesitabas nunca llega a existir. Engagement es la categoría para datos de evento en serie temporal, y requiere un campo de tiempo de evento — el timestamp que ubica cada evento en una línea de tiempo. Aterrizá esos eventos como Profile y le dijiste a la plataforma que describen el estado actual de un sujeto, no una secuencia de momentos. La segmentación por ventana temporal ("compró en los últimos 30 días"), las métricas de engagement y la lógica de recencia entonces no tienen sobre qué pararse, porque el dato nunca se modeló como eventos en el tiempo. La falla aparece una capa abajo, cuando alguien intenta armar el segmento y encuentra que la línea de tiempo no está — y la categoría, fijada una sola vez al crear el stream, es la causa.

El arreglo es elegir la categoría por lo que el dato es, no por lo que se relaciona. Un registro por sujeto, actualizado en el tiempo → Profile. Una cosa que pasó en un momento, con un timestamp → Engagement, y confirmá que el campo de tiempo de evento esté presente y poblado antes de que el stream salga vivo. Datos de referencia o lookup que no son ninguno → Other. Acertar esto es la primera decisión de modelado que tomás aunque pase en la ingesta (principio 1), y es mucho más barato fijarlo bien ahora que re-ingerir después (data streams cubre las tres categorías).

6. Nunca reconciliar lo que ingerís contra lo que usás — el DLO se infla, y el costo trepa por datos que nadie lee

El instinto es ingerir con generosidad: traé el origen entero, cada campo, cada tabla, porque el almacenamiento se siente barato y quizás lo necesites después. Cada stream individual es defendible. El problema es que nadie corre nunca el otro lado del libro mayor — qué de todo este dato ingerido se usa de verdad en un DMO, un segmento, un insight, una activación — así que la brecha entre lo ingerido y lo usado se ensancha en silencio, un stream razonable a la vez.

Lo que pasa de verdad es inflado del DLO: streams refrescando datos que nada de abajo consume, cada corrida pagando el costo de procesamiento de mantener al día algo que ningún segmento lee jamás (principio 11). Rara vez aparece como una sola mala decisión; se acumula. Un campo ingerido para un caso de uso que nunca salió igual refresca en cada corrida. Un origen entero conectado "por tenerlo" aterriza en una cadencia y factura en cada corrida, sin que se lea. Como cada stream es individualmente chico y verde, el inflado es invisible hasta que una revisión de costo pregunta por qué el procesamiento de ingesta es lo que es, y la respuesta es una docena de streams que nadie mapeó a un consumidor.

El arreglo es hacer del ingiere-versus-usa una reconciliación deliberada y recurrente, en vez de algo que asumís. Antes de que un stream salga vivo, nombrá qué lo consume — qué DMO, qué segmento, qué activación; si nada lo hace todavía, no está listo para ingerir en una cadencia. Periódicamente recorré los streams vivos y hacé la misma pregunta de cada uno: un stream cuyos datos nadie lee es un refresco que podés frenar. Ingerí para un consumidor que podés nombrar, no para un "quizás lo necesite" que paga alquiler para siempre (principio 11; el doc de modelo que pide el principio 12 es donde vive esta traza).

7. Leer una consola en verde como "no llegaron datos" — una credencial de conector vencida es idéntica a un origen vacío

El instinto, cuando un equipo de abajo dice "faltan los datos", es mirar el segmento o el DMO y concluir que el origen no tenía nada para mandar — los registros simplemente no están, así que el origen debe estar vacío o atrasado. La consola no te contradice de forma obvia; la ausencia de filas nuevas se ve igual sin importar si el origen no mandó nada o el stream no pudo alcanzarlo. Así que la investigación arranca por la punta equivocada del pipeline.

Lo que pasa de verdad, lo bastante seguido como para chequearlo primero, es que la ingesta falló en vez de que el origen estuviera vacío. La credencial de un conector venció o fue rotada, un token OAuth caducó, el permiso de un bucket de almacenamiento cambió, un límite de API del lado del origen estranguló el pull — y el stream dejó de aterrizar datos mientras todo lo de abajo siguió reportando sobre la última carga buena. "No hay datos nuevos" y "la conexión se rompió en silencio" se presentan idénticos desde la silla del consumidor. Los conectores de almacenamiento de archivos tienen su propia versión: un origen que se supone deja un CSV en un bucket en una agenda deja de hacerlo en silencio, y un bucket vacío se ve abajo exactamente igual que un origen sin registros nuevos (conectores).

El arreglo es hacer de la salud del propio stream la primera hipótesis, no la del origen. Chequeá la última corrida exitosa del stream y su estado de corrida antes de teorizar sobre datos vacíos: un timestamp de última corrida viejo o un estado fallido/de error de autenticación dice que la conexión se rompió, no que el origen se quedó callado. Confirmá que la credencial o el token siga válido, que los permisos y cualquier límite del lado del origen no hayan cambiado, y que el archivo esperado de verdad aterrizó en el bucket. "Faltan datos" es una pregunta de salud del conector antes que una pregunta del origen — depurar la ingesta recorre el orden de diagnóstico completo.


El hilo conductor a través de los siete: la ingesta no te avisa cuando está mal. Elegí upsert y los deletes quedan colgados; re-refrescá de más un origen grande y la factura trepa bajo una corrida verde; usá como clave un campo casi único y los registros se sobrescriben o duplican; poné la cadencia por costumbre y una decisión en tiempo real corre sobre lo de ayer; categorizá mal los eventos y la serie temporal nunca existe; ingerí sin reconciliar contra el uso y el lago se infla; leé un conector roto como un origen vacío y depurás la capa equivocada. Cada uno es silencioso, y la palanca está en el mismo lugar siempre: el modo de refresco y su clave, la cadencia ajustada a la decisión, la categoría fijada por lo que el dato es, y la salud del propio stream chequeada antes de echarle la culpa a algo de abajo. Decidí cada uno de forma deliberada y escribilo — porque la plataforma nunca va a levantar la mano.

Cierre

Estos siete son las fallas de ingesta que Cleon vio morder más fuerte en builds de Data 360. El tema compartido hace eco al resto de este catálogo: la plataforma hace fácil la ingesta fácil y deliberada la correcta. Un registro borrado que no se va, un costo que nadie eligió, una clave que sobrescribe, una cadencia detrás de la decisión, un stream de eventos sin línea de tiempo, un lago que se infla, una credencial que caducó en silencio — ninguno es ruidoso en el momento, y cada uno es un DLO que le miente a todo lo de abajo hasta que alguien nota un número que no puede ser, o un cliente que no debió ser contactado.

Si un gotcha de ingesta mordió a tu equipo y no está acá, escribí a hello@wearecleon.com — lo agregamos, con crédito.

Relacionado

  • Data streams — la unidad de ingesta que estos gotchas configuran: origen a DLO, la categoría y la agenda
  • Conectores — los orígenes, su naturaleza batch-versus-streaming, y las fallas de auth/límite que parecen "sin datos"
  • Modos de refresco — full refresh vs upsert, la clave primaria, y el comportamiento de los deletes detrás de los gotchas 1 y 3
  • La ingesta y el ciclo de vida — por qué un error silencioso de ingesta aparece como un bug aguas abajo tres capas más allá
  • Depurar la ingesta — el orden de diagnóstico: stream que no refresca, conteos mal, registros faltantes o duplicados, salud del conector
  • Style Guide de Ingesta — "¿cómo debería aterrizar este origen?" — streaming vs batch, full vs upsert, y ajustar la cadencia a la decisión

Referencia: