Escribir DAGs de Airflow

Cloud Composer 3 | Cloud Composer 2 | Cloud Composer 1

En esta guía se explica cómo escribir un grafo acíclico dirigido (DAG) de Apache Airflow que se ejecuta en un entorno de Cloud Composer.

Como Apache Airflow no proporciona un aislamiento sólido de DAGs y tareas, te recomendamos que uses entornos de producción y de prueba independientes para evitar interferencias entre DAGs. Para obtener más información, consulta Probar DAGs.

Estructurar un DAG de Airflow

Un DAG de Airflow se define en un archivo de Python y se compone de los siguientes componentes:

  • Definición de DAG
  • Operadores de Airflow
  • Relaciones con operadores

En los siguientes fragmentos de código se muestran ejemplos de cada componente fuera de contexto.

Definición de un DAG

En el siguiente ejemplo se muestra una definición de DAG de Airflow:

import datetime

from airflow import models

default_dag_args = {
    # The start_date describes when a DAG is valid / can be run. Set this to a
    # fixed point in time rather than dynamically, since it is evaluated every
    # time a DAG is parsed. See:
    # https://airflow.apache.org/faq.html#what-s-the-deal-with-start-date
    "start_date": datetime.datetime(2018, 1, 1),
}

# Define a DAG (directed acyclic graph) of tasks.
# Any task you create within the context manager is automatically added to the
# DAG object.
with models.DAG(
    "composer_sample_simple_greeting",
    schedule_interval=datetime.timedelta(days=1),
    default_args=default_dag_args,
) as dag:

Operadores y tareas

Los operadores de Airflow describen el trabajo que se debe realizar. Una tarea task es una instancia específica de un operador.

from airflow.operators.bash import BashOperator
from airflow.operators.python import PythonOperator

    def greeting():
        import logging

        logging.info("Hello World!")

    # An instance of an operator is called a task. In this case, the
    # hello_python task calls the "greeting" Python function.
    hello_python = PythonOperator(task_id="hello", python_callable=greeting)

    # Likewise, the goodbye_bash task calls a Bash script.
    goodbye_bash = BashOperator(task_id="bye", bash_command="echo Goodbye.")

Relaciones de tareas

Las relaciones entre tareas describen el orden en el que se debe completar el trabajo.

# Define the order in which the tasks complete by using the >> and <<
# operators. In this example, hello_python executes before goodbye_bash.
hello_python >> goodbye_bash

Ejemplo de flujo de trabajo de DAG completo en Python

El siguiente flujo de trabajo es una plantilla de DAG completa que consta de dos tareas: una tarea hello_python y una tarea goodbye_bash:


import datetime

from airflow import models

from airflow.operators.bash import BashOperator
from airflow.operators.python import PythonOperator



default_dag_args = {
    # The start_date describes when a DAG is valid / can be run. Set this to a
    # fixed point in time rather than dynamically, since it is evaluated every
    # time a DAG is parsed. See:
    # https://airflow.apache.org/faq.html#what-s-the-deal-with-start-date
    "start_date": datetime.datetime(2018, 1, 1),
}

# Define a DAG (directed acyclic graph) of tasks.
# Any task you create within the context manager is automatically added to the
# DAG object.
with models.DAG(
    "composer_sample_simple_greeting",
    schedule_interval=datetime.timedelta(days=1),
    default_args=default_dag_args,
) as dag:
    def greeting():
        import logging

        logging.info("Hello World!")

    # An instance of an operator is called a task. In this case, the
    # hello_python task calls the "greeting" Python function.
    hello_python = PythonOperator(task_id="hello", python_callable=greeting)

    # Likewise, the goodbye_bash task calls a Bash script.
    goodbye_bash = BashOperator(task_id="bye", bash_command="echo Goodbye.")

    # Define the order in which the tasks complete by using the >> and <<
    # operators. In this example, hello_python executes before goodbye_bash.
    hello_python >> goodbye_bash

Para obtener más información sobre cómo definir DAGs de Airflow, consulta el tutorial de Airflow y los conceptos de Airflow.

Operadores de Airflow

En los ejemplos siguientes se muestran algunos operadores populares de Airflow. Para consultar una referencia oficial de los operadores de Airflow, consulta la referencia de operadores y hooks y el índice de proveedores.

BashOperator

Usa BashOperator para ejecutar programas de línea de comandos.

from airflow.operators import bash

    # Create BigQuery output dataset.
    make_bq_dataset = bash.BashOperator(
        task_id="make_bq_dataset",
        # Executing 'bq' command requires Google Cloud SDK which comes
        # preinstalled in Cloud Composer.
        bash_command=f"bq ls {bq_dataset_name} || bq mk {bq_dataset_name}",
    )

Cloud Composer ejecuta los comandos proporcionados en una secuencia de comandos de Bash en un trabajador de Airflow. El trabajador es un contenedor Docker basado en Debian e incluye varios paquetes.

PythonOperator

Usa PythonOperator para ejecutar código Python arbitrario.

Cloud Composer ejecuta el código Python en un contenedor que incluye paquetes para la versión de imagen de Cloud Composer que se usa en tu entorno.

Para instalar paquetes de Python adicionales, consulta Instalar dependencias de Python.

Google Cloud Operadores

Para ejecutar tareas que usen Google Cloud productos, usa los Google Cloud operadores de Airflow. Por ejemplo, los operadores de BigQuery consultan y procesan datos en BigQuery.

Hay muchos más operadores de Airflow para Google Cloud y servicios individuales proporcionados por Google Cloud. Consulta la lista completa de Google Cloud operadores.

.

from airflow.providers.google.cloud.operators import bigquery
from airflow.providers.google.cloud.transfers import bigquery_to_gcs

    bq_recent_questions_query = bigquery.BigQueryInsertJobOperator(
        task_id="bq_recent_questions_query",
        configuration={
            "query": {
                "query": RECENT_QUESTIONS_QUERY,
                "useLegacySql": False,
                "destinationTable": {
                    "projectId": project_id,
                    "datasetId": bq_dataset_name,
                    "tableId": bq_recent_questions_table_id,
                },
            }
        },
        location=location,
    )

EmailOperator

Usa EmailOperator para enviar correos desde un DAG. Para enviar correos desde un entorno de Cloud Composer, configura tu entorno para que use SendGrid.

from airflow.operators import email

    # Send email confirmation (you will need to set up the email operator
    # See https://cloud.google.com/composer/docs/how-to/managing/creating#notification
    # for more info on configuring the email operator in Cloud Composer)
    email_summary = email.EmailOperator(
        task_id="email_summary",
        to="{{var.value.email}}",
        subject="Sample BigQuery notify data ready",
        html_content="""
        Analyzed Stack Overflow posts data from {min_date} 12AM to {max_date}
        12AM. The most popular question was '{question_title}' with
        {view_count} views. Top 100 questions asked are now available at:
        {export_location}.
        """.format(
            min_date=min_query_date,
            max_date=max_query_date,
            question_title=(
                "{{ ti.xcom_pull(task_ids='bq_read_most_popular', "
                "key='return_value')[0][0] }}"
            ),
            view_count=(
                "{{ ti.xcom_pull(task_ids='bq_read_most_popular', "
                "key='return_value')[0][1] }}"
            ),
            export_location=output_file,
        ),
    )

Notificaciones sobre fallos del operador

Define email_on_failure como True para enviar una notificación por correo cuando falle un operador del DAG. Para enviar notificaciones por correo electrónico desde un entorno de Cloud Composer, debes configurar tu entorno para que use SendGrid.

from airflow import models

default_dag_args = {
    "start_date": yesterday,
    # Email whenever an Operator in the DAG fails.
    "email": "{{var.value.email}}",
    "email_on_failure": True,
    "email_on_retry": False,
    "retries": 1,
    "retry_delay": datetime.timedelta(minutes=5),
    "project_id": project_id,
}

with models.DAG(
    "composer_sample_bq_notify",
    schedule_interval=datetime.timedelta(weeks=4),
    default_args=default_dag_args,
) as dag:

Directrices de flujo de trabajo de DAG

  • Coloca las bibliotecas de Python personalizadas en un archivo ZIP de un DAG en un directorio anidado. No coloque bibliotecas en el nivel superior del directorio DAGs.

    Cuando Airflow analiza la carpeta dags/, solo busca DAGs en módulos de Python que estén en el nivel superior de la carpeta DAGs y en el nivel superior de un archivo ZIP que también se encuentre en la carpeta dags/ de nivel superior. Si Airflow encuentra un módulo de Python en un archivo ZIP que no contiene las subcadenas airflow y DAG, Airflow detiene el procesamiento del archivo ZIP. Airflow solo devuelve los DAGs encontrados hasta ese momento.

  • Para que haya tolerancia a fallos, no definas varios objetos DAG en el mismo módulo de Python.

  • No uses SubDAGs. En su lugar, agrupa las tareas dentro de los DAGs.

  • Coloca los archivos necesarios en el momento del análisis del DAG en la carpeta dags/, no en la carpeta data/.

  • Implementa pruebas unitarias para tus DAGs.

  • Prueba los DAGs desarrollados o modificados tal como se recomienda en las instrucciones para probar DAGs.

  • Comprueba que los DAGs desarrollados no aumenten demasiado los tiempos de análisis de DAGs.

  • Las tareas de Airflow pueden fallar por varios motivos. Para evitar fallos en ejecuciones completas de DAG, te recomendamos que habilites los reintentos de tareas. Si se establece el número máximo de reintentos en 0, no se realizará ningún reintento.

    Te recomendamos que anules la opción default_task_retries con un valor para los reintentos de tareas que no sea 0. Además, puedes definir el retries parámetro a nivel de tarea.

  • Si quieres usar GPUs en tus tareas de Airflow, crea un clúster de GKE independiente basado en nodos que usen máquinas con GPUs. Usa GKEStartPodOperator para ejecutar tus tareas.

  • Evita ejecutar tareas que consuman mucha CPU y memoria en el grupo de nodos del clúster en el que se ejecutan otros componentes de Airflow (programadores, trabajadores y servidores web). En su lugar, usa KubernetesPodOperator o GKEStartPodOperator.

  • Cuando implementes DAGs en un entorno, sube solo los archivos que sean absolutamente necesarios para interpretar y ejecutar DAGs en la carpeta /dags.

  • Limita el número de archivos DAG en la carpeta /dags.

    Airflow analiza continuamente los DAGs de la carpeta /dags. El análisis es un proceso que recorre en bucle la carpeta de DAGs. El número de archivos que se deben cargar (con sus dependencias) influye en el rendimiento del análisis de DAGs y la programación de tareas. Es mucho más eficiente usar 100 archivos con 100 DAGs cada uno que 10.000 archivos con 1 DAG cada uno, por lo que se recomienda esta optimización. Esta optimización es un equilibrio entre el tiempo de análisis y la eficiencia de la creación y la gestión de DAGs.

    También puedes plantearte, por ejemplo, implementar 10.000 archivos DAG. Para ello, puedes crear 100 archivos ZIP, cada uno de los cuales contenga 100 archivos DAG.

    Además de los consejos anteriores, si tienes más de 10.000 archivos DAG, puede que te convenga generar DAGs de forma programática. Por ejemplo, puedes implementar un único archivo DAG de Python que genere un número determinado de objetos DAG (por ejemplo, 20 o 100 objetos DAG).

  • No utilices operadores de Airflow obsoletos. En su lugar, usa sus alternativas actualizadas.

Preguntas frecuentes sobre cómo escribir DAGs

¿Cómo puedo minimizar la repetición de código si quiero ejecutar tareas iguales o similares en varios DAGs?

Te recomendamos que definas bibliotecas y envoltorios para minimizar la repetición de código.

¿Cómo puedo reutilizar código entre archivos DAG?

Coloca tus funciones de utilidad en una biblioteca local de Python e importa las funciones. Puedes hacer referencia a las funciones de cualquier DAG ubicado en la carpeta dags/ del bucket de tu entorno.

¿Cómo puedo minimizar el riesgo de que surjan definiciones diferentes?

Por ejemplo, tienes dos equipos que quieren agregar datos sin procesar en métricas de ingresos. Los equipos escriben dos tareas ligeramente diferentes que hacen lo mismo. Define bibliotecas para trabajar con los datos de ingresos de forma que los implementadores de DAG deban aclarar la definición de los ingresos que se están agregando.

¿Cómo puedo definir dependencias entre DAGs?

Depende de cómo quieras definir la dependencia.

Si tienes dos DAGs (DAG A y DAG B) y quieres que DAG B se active después de DAG A, puedes poner un TriggerDagRunOperator al final de DAG A.

Si el DAG B solo depende de un artefacto que genera el DAG A, como un mensaje de Pub/Sub, puede que un sensor sea más adecuado.

Si el DAG B está integrado estrechamente con el DAG A, es posible que puedas combinar los dos DAGs en uno.

¿Cómo puedo transferir IDs de ejecución únicos a un DAG y a sus tareas?

Por ejemplo, quieres transferir nombres de clústeres de Dataproc y rutas de archivos.

Puedes generar un ID único aleatorio devolviendo str(uuid.uuid4()) en un PythonOperator. De esta forma, el ID se coloca en XComs para que puedas hacer referencia a él en otros operadores mediante campos de plantilla.

Antes de generar un uuid, plantéate si sería más útil un ID específico de DagRun. También puede hacer referencia a estos IDs en sustituciones de Jinja mediante macros.

¿Cómo separo las tareas de un DAG?

Cada tarea debe ser una unidad de trabajo idempotente. Por lo tanto, debes evitar encapsular un flujo de trabajo de varios pasos en una sola tarea, como un programa complejo que se ejecute en un PythonOperator.

¿Debo definir varias tareas en un solo DAG para agregar datos de varias fuentes?

Por ejemplo, tiene varias tablas con datos sin procesar y quiere crear agregaciones diarias para cada tabla. Las tareas no dependen entre sí. ¿Deberías crear una tarea y un DAG para cada tabla o crear un DAG general?

Si no te importa que todas las tareas compartan las mismas propiedades a nivel de DAG, como schedule_interval, puedes definir varias tareas en un solo DAG. De lo contrario, para minimizar la repetición de código, se pueden generar varios DAGs a partir de un único módulo de Python colocándolos en el globals() del módulo.

¿Cómo limito el número de tareas simultáneas que se ejecutan en un DAG?

Por ejemplo, quieres evitar superar los límites o las cuotas de uso de la API o ejecutar demasiados procesos simultáneos.

Puedes definir grupos de Airflow en la interfaz web de Airflow y asociar tareas a grupos que ya tengas en tus DAGs.

Preguntas frecuentes sobre el uso de operadores

¿Debo usar DockerOperator?

No recomendamos usar DockerOperator, a menos que se utilice para iniciar contenedores en una instalación de Docker remota (no en el clúster de un entorno). En un entorno de Cloud Composer, el operador no tiene acceso a los daemons de Docker.

En su lugar, usa KubernetesPodOperator o GKEStartPodOperator. Estos operadores inician pods de Kubernetes en clústeres de Kubernetes o de GKE, respectivamente. Ten en cuenta que no recomendamos lanzar pods en el clúster de un entorno, ya que esto puede provocar una competencia por los recursos.

¿Debo usar SubDagOperator?

No recomendamos usar SubDagOperator.

Usa las alternativas que se sugieren en Agrupar tareas.

¿Debo ejecutar código Python solo en PythonOperators para separar completamente los operadores de Python?

En función de tu objetivo, tienes varias opciones.

Si solo te preocupa mantener separadas las dependencias de Python, puedes usar PythonVirtualenvOperator.

Usa la KubernetesPodOperator. Este operador te permite definir pods de Kubernetes y ejecutarlos en otros clústeres.

¿Cómo puedo añadir paquetes binarios personalizados o que no sean de PyPI?

Puedes instalar paquetes alojados en repositorios de paquetes privados.

¿Cómo puedo transferir argumentos de forma uniforme a un DAG y a sus tareas?

Puedes usar la compatibilidad integrada de Airflow con plantillas Jinja para transferir argumentos que se puedan usar en campos de plantilla.

¿Cuándo se produce la sustitución de plantillas?

La sustitución de plantillas se produce en los trabajadores de Airflow justo antes de que se llame a la función pre_execute de un operador. En la práctica, esto significa que las plantillas no se sustituyen hasta justo antes de que se ejecute una tarea.

¿Cómo puedo saber qué argumentos de operador admiten la sustitución de plantillas?

Los argumentos de operador que admiten la sustitución de plantillas Jinja2 se marcan explícitamente como tales.

Busca el campo template_fields en la definición del operador, que contiene una lista de nombres de argumentos que se someten a sustitución de plantillas.

Por ejemplo, consulta BashOperator, que admite plantillas para los argumentos bash_command y env.

Operadores de Airflow obsoletos y eliminados

Los operadores de Airflow que se indican en la siguiente tabla están obsoletos:

  • No utilices estos operadores en tus DAGs. En su lugar, usa los operadores de sustitución actualizados que se proporcionan.

  • Si un operador aparece como eliminado, significa que ya no está disponible en una de las compilaciones de Airflow publicadas en Cloud Composer 3.

  • Si un operador aparece como programado para eliminarse, significa que está obsoleto y se eliminará en una compilación futura de Airflow.

  • Si un operador aparece como ya retirado en los proveedores de Google más recientes, significa que se ha retirado en la versión más reciente del paquete apache-airflow-providers-google. Al mismo tiempo, Cloud Composer sigue usando la versión de este paquete en la que el operador aún no se ha quitado.

Operador obsoleto Estado Operador de sustitución Sustitución disponible a partir de
CreateAutoMLTextTrainingJobOperator Retirado SupervisedFineTuningTrainOperator composer-3-airflow-2.9.3-build.1
composer-3-airflow-2.9.1-build.8
GKEDeploymentHook Retirado GKEKubernetesHook Todas las versiones
GKECustomResourceHook Retirado GKEKubernetesHook Todas las versiones
GKEPodHook Retirado GKEKubernetesHook Todas las versiones
GKEJobHook Retirado GKEKubernetesHook Todas las versiones
GKEPodAsyncHook Retirado GKEKubernetesAsyncHook Todas las versiones
SecretsManagerHook Retirado GoogleCloudSecretManagerHook composer-3-airflow-2.7.3-build.6
BigQueryExecuteQueryOperator Retirado BigQueryInsertJobOperator Todas las versiones
BigQueryPatchDatasetOperator Retirado BigQueryUpdateDatasetOperator Todas las versiones
DataflowCreateJavaJobOperator Retirado beam.BeamRunJavaPipelineOperator Todas las versiones
DataflowCreatePythonJobOperator Retirado beam.BeamRunPythonPipelineOperator Todas las versiones
DataprocSubmitPigJobOperator Retirado DataprocSubmitJobOperator Todas las versiones
DataprocSubmitHiveJobOperator Retirado DataprocSubmitJobOperator Todas las versiones
DataprocSubmitSparkSqlJobOperator Retirado DataprocSubmitJobOperator Todas las versiones
DataprocSubmitSparkJobOperator Retirado DataprocSubmitJobOperator Todas las versiones
DataprocSubmitHadoopJobOperator Retirado DataprocSubmitJobOperator Todas las versiones
DataprocSubmitPySparkJobOperator Retirado DataprocSubmitJobOperator Todas las versiones
BigQueryTableExistenceAsyncSensor Retirado BigQueryTableExistenceSensor Todas las versiones
BigQueryTableExistencePartitionAsyncSensor Retirado BigQueryTablePartitionExistenceSensor Todas las versiones
CloudComposerEnvironmentSensor Retirado CloudComposerCreateEnvironmentOperator, CloudComposerDeleteEnvironmentOperator, CloudComposerUpdateEnvironmentOperator Todas las versiones
GCSObjectExistenceAsyncSensor Retirado GCSObjectExistenceSensor Todas las versiones
GoogleAnalyticsHook Retirado GoogleAnalyticsAdminHook Todas las versiones
GoogleAnalyticsListAccountsOperator Retirado GoogleAnalyticsAdminListAccountsOperator Todas las versiones
GoogleAnalyticsGetAdsLinkOperator Retirado GoogleAnalyticsAdminGetGoogleAdsLinkOperator Todas las versiones
GoogleAnalyticsRetrieveAdsLinksListOperator Retirado GoogleAnalyticsAdminListGoogleAdsLinksOperator Todas las versiones
GoogleAnalyticsDataImportUploadOperator Retirado GoogleAnalyticsAdminCreateDataStreamOperator Todas las versiones
GoogleAnalyticsDeletePreviousDataUploadsOperator Retirado GoogleAnalyticsAdminDeleteDataStreamOperator Todas las versiones
DataPipelineHook Retirado DataflowHook composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
CreateDataPipelineOperator Retirado DataflowCreatePipelineOperator composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
RunDataPipelineOperator Retirado DataflowRunPipelineOperator composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
AutoMLDatasetLink Obsoleto, retirada programada TranslationLegacyDatasetLink composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
AutoMLDatasetListLink Obsoleto, retirada programada TranslationDatasetListLink composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
AutoMLModelLink Obsoleto, retirada programada TranslationLegacyModelLink composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
AutoMLModelTrainLink Obsoleto, retirada programada TranslationLegacyModelTrainLink composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
AutoMLModelPredictLink Obsoleto, retirada programada TranslationLegacyModelPredictLink composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
AutoMLBatchPredictOperator Retirado vertex_ai.batch_prediction_job composer-3-airflow-2.9.3-build.4
AutoMLPredictOperator Obsoleto, retirada programada vertex_aigenerative_model. TextGenerationModelPredictOperator, translate.TranslateTextOperator composer-3-airflow-2.7.3-build.6
PromptLanguageModelOperator Retirado TextGenerationModelPredictOperator composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
GenerateTextEmbeddingsOperator Retirado TextEmbeddingModelGetEmbeddingsOperator composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
PromptMultimodalModelOperator Retirado GenerativeModelGenerateContentOperator composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
PromptMultimodalModelWithMediaOperator Retirado GenerativeModelGenerateContentOperator composer-3-airflow-2.9.1-build.0
composer-3-airflow-2.7.3-build.9
DataflowStartSqlJobOperator Retirado DataflowStartYamlJobOperator composer-3-airflow-2.9.3-build.1
composer-3-airflow-2.9.1-build.8
LifeSciencesHook Obsoleto, retirada programada Hook de operadores de Batch para Google Cloud Pendiente de anunciar
DataprocScaleClusterOperator Obsoleto, retirada programada DataprocUpdateClusterOperator Pendiente de anunciar
MLEngineStartBatchPredictionJobOperator Obsoleto, retirada programada CreateBatchPredictionJobOperator Pendiente de anunciar
MLEngineManageModelOperator Obsoleto, retirada programada MLEngineCreateModelOperator, MLEngineGetModelOperator Pendiente de anunciar
MLEngineGetModelOperator Obsoleto, retirada programada GetModelOperator Pendiente de anunciar
MLEngineDeleteModelOperator Obsoleto, retirada programada DeleteModelOperator Pendiente de anunciar
MLEngineManageVersionOperator Obsoleto, retirada programada MLEngineCreateVersion, MLEngineSetDefaultVersion, MLEngineListVersions, MLEngineDeleteVersion Pendiente de anunciar
MLEngineCreateVersionOperator Obsoleto, retirada programada Parámetro parent_model para operadores de Vertex AI Pendiente de anunciar
MLEngineSetDefaultVersionOperator Obsoleto, retirada programada SetDefaultVersionOnModelOperator Pendiente de anunciar
MLEngineListVersionsOperator Obsoleto, retirada programada ListModelVersionsOperator Pendiente de anunciar
MLEngineDeleteVersionOperator Obsoleto, retirada programada DeleteModelVersionOperator Pendiente de anunciar
MLEngineStartTrainingJobOperator Obsoleto, retirada programada CreateCustomPythonPackageTrainingJobOperator Pendiente de anunciar
MLEngineTrainingCancelJobOperator Obsoleto, retirada programada CancelCustomTrainingJobOperator Pendiente de anunciar
LifeSciencesRunPipelineOperator Obsoleto, retirada programada Operadores de Google Cloud Batch Pendiente de anunciar
MLEngineCreateModelOperator Obsoleto, retirada programada Operador de Vertex AI correspondiente Pendiente de anunciar

Siguientes pasos