BULK API v2: 2 veces más rápida con la mitad de código

Una de las novedades que quizás pasaron inadvertidas en la última release de Winter ’18, fue la nueva versión de la BULK API, denominada BULK API v2, disponible en v41.0.

Esta nueva versión, sigue siendo una API REST, que utiliza los verbos HTTP para crear Jobs, cerrar/abortar, eliminar y obtener información al respecto, aportando novedades para el programador y una mejora del rendimiento para el usuario final.

En esta entrada, se muestran las diferencias entre ambas versiones y se compara el rendimiento.

Recordemos que el uso de BULK API en su modo Parallel, según la documentación de Salesforce, ofrece un grado de paralelismo en una horquilla de 15 y 20, lo que permite normalmente a los clientes, cargar alrededor de 15-20 millones de registros cada hora en cargas bien optimizadas.

Comparación entre versiones

Las novedades de esta nueva versión están orientadas al uso de la API:

  1. Ya no es necesaria la gestión de Batches dentro de 1 Job.
    1. Dicho así parece simple, pero aquellos que hemos programado en este esquema, veremos simplificado el código necesario en un % elevado
  2. Los límites para el uso de esta API, se simplifican:
    1. 100 millones de registros/día
    2. Contenido de mensaje que no superen los 150MB codificados en B64 al llegar a Salesforce (lo que significa a ojo de buen cubero, como máximo mensajes con payload de 100 MB en origen)
  3. La velocidad de ejecución:
    1. Como se observa en las mediciones realizadas llega a ser x2

De menor importancia, pero muy útil:

    • En la v2 se ofrece un nuevo servicio, accesible con el verbo GET, para consultar el estado de los Jobs, pudiendo solicitar todos aquellos Jobs que cumplen ciertas condiciones
    • Además la v2 soporta 6 tipos de separadores de campos distintos (backquote, caret, comma, pipe, semicolon, y tab) lo que evita tener que modificar nuestros ficheros origen (mayor flexibilidad lo que comporta menos código)
    • (22/2/2018): con la ayuda de un lector, hemos comprobado que actualmente la v41  no soportar el modo Serial en la API:

El modo Serial aún no está soportado en esta versión

    El modo Serial aún no está soportado en esta versión

Comparación entre ambas APIs

Simplificación del proceso

En la V1 la creación de trabajos requería:

  1. Autenticación
  2. Creación del Job
  3. Gestión de los Batches
    1. Creación individual de cada Batches
    2. Empaquetar cada Batch en el límite
    3. Envío de los datos del Batch
    4. Gestión individual del estado de las cargas
    5. Confirmación/Retry en caso de incidencias
  4. Cierre del Batch (para inicio de ejecución)
  5. Pooling del estado del Job
  6. Gestión de los resultados (obteniendo la información de los registros ejecutados/correctos/error)

En la V2, este proceso se simplifica:

  1. Autenticación
  2. Creación del Job (simple o multipart)
  3. Gestión de los Batches
    1. Creación individual de cada Batche
    2. Empaquetar cada Batch en el límite
    3. Envío de los datos del Batch Job
    4. Gestión individual del estado de las cargas
    5. Confirmación/Retry en caso de incidencias
  4. Cierre del Batch Job (para iniciar ejecución)
  5. Pooling del estado del Job, mediante invocación del servicio de intención de información del Job
  6. Gestión de los resultados (obteniendo la información referente a los registros ejecutados/correctos/error)

Es decir:

  • Salesforce ahora libera al desarrollador de la segmentación y tratamiento de los Batches, y únicamente requiere la creación del Job, Upload de los datos (si no utilizamos Multipart), y chequeo de estado con obtención de resultados
  • La segmentación de los datos se realiza ahora de forma que cada segmento, contiene 10.000 registros, como podemos ver en la página estado del Job, lo que disminuye el número de Batches que gestiona Salesforce internamente.
  • Se sigue la regla del 10×10: si el proceso tardara más de 10′, Salesforce lo marcaría como a Reintentar, hasta un máximo de 10 veces (en esta circunstancia el Job se da por Failed).

Detalle de un Job con la BULK API v2

Por tanto, la parte más compleja queda eliminada del proceso, simplificándolo en gran medida.

Operaciones disponibles en v2 y como usarlas

Las operaciones y los verbos utilizados en la API, son intuitivos, pero se recomienda estar muy atento al uso de las cabeceras que se indican en la documentación oficial de Salesforce, para evitar errores inesperados.

El proyecto Java, construido para esta entrada, disponible como Repositorio público, puede ser una opción,  para observar como son los valores, tanto para las cabeceras, como los Payload y respuestas, y así evitar problemas inesperados.

Autenticación

Sin cambios, la autenticación se realiza obteniendo el token oAuth como se realiza en v1.

Creación de un Job Simple

Existen 2 posibilidades para crear un Job. La opción, que denominamos Simple, consta de varios pasos: Creación, Upload de datos,  y Cierre del Job (inicio del procesamiento en Salesforce) y opcionalmente obtener información y estado final de los registros gestionados.

Para la creación tan solo se requiere,  el envío de una petición POST al endpoint  /services/data/vXX.X/jobs/ingest/. En el cuerpo del mensaje se indica:

  • El objeto destino, por ejemplo Persona__c, Account, etc.
  • La operación bulk a realizar: insert, update, delete, etc.
  • Los parámetros adicionales que caracterizan la lectura de los datos, o la naturaleza del Job (paralelismo, concurrencia, etc.).

Es imprescindible leer la documentación (al final del artículo todos los enlaces disponibles) para entender las posibilidades y restricciones que impone la API.

Ejemplo llamada Java Creación Job para la BULK API v2

Upload de Datos en un Job Simple creado

El Upload de datos, requiere de haber realizado la llamada anterior con éxito, dado que en la respuesta, se obtiene el endpoint de datos, donde deben enviarse los datos (100 MB como máximo aproximadamente – ver la sección de límites).

Obtenido el endpoint, solo se requiere un PUT a esa URL, pero debemos ser cuidadosos con la construcción de las cabeceras, y de los encodings (siguiendo el ejemplo del código disponible en el REPO, se obtiene como hacerlo correctamente).

Ejemplo llamada Java para el envío de datos al Job creado para la BULK API v2

Cerrar el Job

Con todos los datos enviados, se requiere de una llamada con el verbo PATCH, sobre el endpoint /services/data/vXX.X/jobs/ingest/jobID, indicando a Salesforce que todos los datos han sido enviados, y debe iniciar el procesamiento (construcción de los batches internos y toma de resultados).

Ejemplo llamada Java para el cierre del Job creado para la BULK API v2

Creación de un Job Multipart

Alternativamente a los pasos anteriores, es posible usar una única invocación para la creación, upload y cierre.

Para ello se requiere la construcción de un mensaje Multipart, siguiendo el formato indicado en la documentación, con el verbo POST hacía el endpoint /services/data/vXX.X/jobs/ingest/.

Ejemplo llamada Java Creación Job Multipart para la BULK API v2

Obtener estado del Job

Los estados del Job son: Open, UploadComplete. InProgress, JobComplete, Failed, Aborted. Existen ciertas restricciones,  como por ejemplo: para eliminar un Job, no puede estar en estado inProgress, o aparece el siguiente mensaje:

[{"errorCode":"API_ERROR","message":"Error encountered when deleting the job because the job is not terminated"}]

Consultar su estado requiere una invocación con el verbo GET al endpoint /services/data/vXX.X/jobs/ingest/jobID.

Ejemplo llamada Java para la consulta del estado de un Job para la BULK API v2

Información que se obtiene de un Job

La información que se obtiene de un Job, es completa, fácil de obtener y consumir. El objeto JSON retornado es:

{
"id": "7501r0000097DEBAA2",
"operation": "insert",
"object": "Contact",
"createdById": "005w000000484LsAAI",
"createdDate": "2017-12-17T09:29:10.000+0000",
"systemModstamp": "2017-12-17T09:29:10.000+0000",
"state": "Open",
"concurrencyMode": "Parallel",
"contentType": "CSV",
"apiVersion": 41.0,
"jobType": "V2Ingest",
"contentUrl": "services/data/v41.0/jobs/ingest/7501r0000097DEBAA2/batches",
"lineEnding": "LF",
"columnDelimiter": "COMMA",
"retries": 0,
"totalProcessingTime": 0,
"apiActiveProcessingTime": 0,
"apexProcessingTime": 0
}

Rendimiento comparado entre versiones

Hasta aquí todo son bondades para los programadores que trabajen con la API, pero poca repercusión tiene para los usuarios finales que la utilizan mediante herramientas de terceros, como ETLs, Data Loader, etc.

Para comparar tiempos, se ha construido un cliente Java sencillo con Web Service Connector, (enlace al repositorio) y se ha ejecutado una batida de pruebas tomando tiempos de ejecución de ambas versiones de la API (durante fin de semana previo a Navidad, cuando las instancias supuestamente estarán con baja ocupación).

Los resultados han sido:

OPERACIÓN y volumen Tiempo MEDIO empleado por la BULK API v1 Tiempo MEDIO empleado por la BULK API v2 Diferencial porcentual
INSERT 250K 131» 41» -220%
INSERT 500K 251» 138» -82%
INSERT 1M 442» 263» -68%
SOFT DELETE 500K 160» 148» -8%
UPDATE 250K 31» 22» -41%
UPDATE 500K 142» 123» -15%
UPSERT 500K 178» 110» -62%
  • Los tiempos se expresan en segundos
  • El volumen de registros se expresa en miles (k), es decir 250k indican 250.000 registros
  • Un diferencial negativo, implica una mejora del rendimiento
  • La operación Hard Delete no está actualmente disponible en la API V2
Resumen de Resultados porcentuales obtenidos

Conclusiones

Esta nueva versión v2, mejora la anterior tanto en uso, simplificándolo, como en rendimiento, mejorándolo, lo que supone que todos los usuarios, tanto técnicos como finales, se verán beneficiados.

Antes de usarla debemos comprobar que:

  • la operación que debemos realizar está disponible en esta API
  • seguimos aplicanado las buenas prácticas de BULK: sobre la gestión de bloqueos para las relaciones master-detail, para relaciones Look-up que no sean optional, roll-up summary fields, modificaciones de roles y grupos, mantener siempre 20 batches disponibles para procesamiento, etc.

Recordar que para cargas masivas se recomienda desactivar todas aquellas operaciones que pueden perjudicar el rendimiento de la carga, como triggers, workflow rules, recálculos de la jerarquía de roles, etc.

Enlaces interesantes

Anuncio publicitario

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.