Are you satisfied with the way you currently manage the dependencies in your ETL? In part 1 of this article, I talked about the features I’m expecting from a dependency management system, and what are the main possibilities offered (directly or indirectly) by SAP Data Services. Now (part 2 of the article), I’m going to propose an architecture (structure and expected behavior) for a dependency management system inside Data Services. The implementation details will come in part 3, while a feedback on how it went “in real life” as well as possible improvements will come in part 4.
La arquitectura propuesta
What I’m going to develop now is the following: an improvement of the “One job with all processes inside” architecture.
Las principales características de esta arquitectura son:
- Gestión de múltiples dependencias (un flujo puede depender de múltiples procesos)
- Un gracioso reinicio es posible. El reinicio ETL completo también es una opción.
Primero debemos crear dos tablas, FLOW_DEPENDENCIES y FLOW_STATUS.
- La tabla FLOW_DEPENDENCIES tiene dos columnas FLOW_NAME y PREREQUISITE. Tiene una línea para cada prerrequisito.
Para el ejemplo siguiente (dependencias de flujo lógico en un trabajo) ...
... relataremos la tabla FLOW_DEPENDENCIES de la siguiente manera:
Por supuesto, no puede implementar directamente estas dependencias lógicas en los Servicios de datos, por lo que es necesario encadenarlos uno tras otro.
La tabla se actualiza manualmente cada vez que hay un nuevo requisito previo. Un flujo sin requisito previo no necesita ninguna fila en esta tabla (ver flujo A por ejemplo).
La tabla FLOW_STATUS realiza un seguimiento de los diferentes estados de flujo (ya se ejecutan, Sucesos, Fallas, Requisitos previos faltantes) para cada ejecución del trabajo principal. Las columnas 3 son JOB_KEY (que contiene una clave sustituta para cada nueva ejecución del trabajo), FLOW_NAME y STATUS.
Para dejar las cosas claras, imaginemos que ejecutaremos el trabajo por primera vez (JOB_KEY = 1).
- El flujo A no tiene ningún requisito previo, por lo que se permite ejecutar. Tiene éxito. Se inserta una fila con STATUS = Success en la tabla FLOW_STATUS.
- El flujo B tiene un requisito previo de acuerdo con la tabla FLOW_DEPENDENCIES (el flujo A), por lo que comprueba el estado del flujo A en la misma ejecución. Resulta que el flujo A fue exitoso, por lo que se permite que el flujo B se ejecute. Desafortunadamente, falla por una razón desconocida. Se inserta una fila con STATUS = Failure en la tabla FLOW_STATUS.
- Se permite que el flujo C se ejecute de acuerdo con la misma lógica que para el flujo B. Se ejecuta con éxito. Se inserta una fila con STATUS = Success en la tabla FLOW_STATUS.
- El flujo D tiene dos pre-requisitos de acuerdo con la tabla FLOW_DEPENDENCIES (flujos B y C). Comprueba el estado de ambos. A medida que el flujo B falla, el flujo D no se deja correr. Se inserta una fila con STATUS = Requisito faltante en la tabla FLOW_STATUS.
- Se permite que el flujo E se ejecute de acuerdo con el mismo flujo lógico B. Se ejecuta correctamente. Se inserta una fila con STATUS = Success en la tabla FLOW_STATUS.
- El flujo F tiene un requisito previo (flujo D). Pero como el estado del flujo D es "Requisito faltante", el flujo F también no se permite correr. Se inserta un estado similar en la tabla de estado de flujo.
A continuación se muestran las filas insertadas en la tabla FLOW_STATUS durante esta ejecución del trabajo.
Una vez corregida la causa del error en el flujo B, podemos volver a ejecutar el trabajo. JOB_KEY será igual a 2, e indicaremos al trabajo que debe comprobar los estados del trabajo anterior (en el que JOB_KEY = 1).
- El trabajo comienza comprobando el estado del flujo A en la tabla FLOW_STATUS con JOB_KEY = 1. Como el estado es igual a Éxito, el flujo A no necesita ejecutarse en este trabajo. Se inserta una fila con STATUS = "Already run" en la tabla FLOW_STATUS.
- El estado del flujo B con JOB_KEY = 1 es "Fallo". Por lo tanto, el flujo B debe ejecutarse durante este trabajo. A continuación, el trabajo comprueba el estado del requisito previo (el flujo A) para JOB_KEY = 2. Resulta que el flujo A ya estaba ejecutado, por lo que se permite que el flujo B se ejecute. Se ejecuta con éxito. Se inserta una fila con STATUS = Success en la tabla FLOW_STATUS.
- Los flujos restantes siguen una lógica similar.
A continuación se muestran las filas insertadas en la tabla FLOW_STATUS durante esta ejecución del trabajo.
Como puede ver, esta solución gestiona las dependencias de ETL, mantiene el rastro del historial de carga y permite fácilmente una re-ejecución parcial del ETL si una parte de éste falla. En la siguiente parte os daré los detalles de la implementación de Data Services: qué scripts / flows / functions / etc. Debemos usar ¿Cómo hacemos este sistema fácil de implementar y mantener? Hasta entonces, espero su opinión sobre esta arquitectura propuesta. ¿Se ve bien? ¿Cómo lo mejorarías? Háganme saber con un comentario a continuación.