Airflow 仅运行最新的气流DAG

Airflow 仅运行最新的气流DAG,airflow,airflow-scheduler,Airflow,Airflow Scheduler,假设我想用气流运行一个非常简单的ETL DAG: 它检查DB2中的最后一次插入时间,并将较新的行从DB1加载到DB2(如果有) 有一些可以理解的要求: 计划每小时运行一次,前几次运行将持续1小时以上 第一次运行应处理一个月的数据,持续72小时 因此,第二次运行应处理最后72小时,持续7.2小时 第三个过程7.2小时,在一小时内完成 从那时起,它每小时运行一次 DAG运行时,不要启动下一个DAG,而是跳过它 如果时间已过触发事件,且DAG未启动,则不要随后启动它 还有其他DAG,DAG应独立执

假设我想用气流运行一个非常简单的ETL DAG: 它检查DB2中的最后一次插入时间,并将较新的行从DB1加载到DB2(如果有)

有一些可以理解的要求:

  • 计划每小时运行一次,前几次运行将持续1小时以上
    • 第一次运行应处理一个月的数据,持续72小时
    • 因此,第二次运行应处理最后72小时,持续7.2小时
    • 第三个过程7.2小时,在一小时内完成
    • 从那时起,它每小时运行一次
  • DAG运行时,不要启动下一个DAG,而是跳过它
  • 如果时间已过触发事件,且DAG未启动,则不要随后启动它
  • 还有其他DAG,DAG应独立执行
  • 我发现这些参数和运算符有点混淆,它们之间的区别是什么

    • 取决于过去
    • catchup
    • 回填
    • LatestOnlyOperator
    我应该使用哪一个,以及哪一个LocalExecutor


    注:已经有一个非常类似的,但它并不累人。

    这一个满足我的要求。DAG每分钟运行一次,我的“主要”任务持续90秒,因此它应该跳过每秒钟的运行。 我使用了一个
    shortcircuit操作符
    来检查当前运行是否是当前唯一的运行(在
    aiffair
    db的
    dag\u运行
    表中查询),以及
    catchup=False
    来禁用回填。 但是,我不能正确地使用应该执行类似操作的
    LatestOnlyOperator

    DAG文件 util.py 福比
    确认:此答案基于。

    DAG max_active_runs=1与catchup=False组合将解决此问题。

    DAG max_active_runs=1与catchup=False组合,并在开始处添加一个虚拟任务(启动任务的排序),wait_for_DOWNDEMENT=True。 从LatestOnlyOperator开始-如果上一次执行尚未完成,它将有助于避免重新运行任务。 或者创建“启动”任务作为LatestOnlyOperator,并确保第一处理层的所有TAK部分都连接到它。但请注意——根据文档“注意,如果给定的DAG_运行被标记为外部触发,则不会跳过下游任务。”

    import os
    import sys
    from datetime import datetime
    import airflow
    from airflow import DAG
    from airflow.operators.python_operator import PythonOperator, ShortCircuitOperator
    
    import foo
    import util
    
    default_args = {
        'owner': 'airflow',
        'depends_on_past': True,
        'start_date': datetime(2018, 2, 13), # or any date in the past
        'email': ['services@mydomain.com'],
        'email_on_failure': True}
    
    dag = DAG(
        'test90_dag',
        default_args=default_args,
        schedule_interval='* * * * *',
        catchup=False)
    
    condition_task = ShortCircuitOperator(
        task_id='skip_check',
        python_callable=util.is_latest_active_dagrun,
        provide_context=True,
        dag=dag)
    
    py_task = PythonOperator(
        task_id="test90_task",
        python_callable=foo.bar,
        provide_context=True,
        dag=dag)
    
    airflow.utils.helpers.chain(condition_task, py_task)
    
    import logging
    from datetime import datetime
    from airflow.hooks.postgres_hook import PostgresHook
    
    def get_num_active_dagruns(dag_id, conn_id='airflow_db'):
        # for this you have to set this value in the airflow db
        airflow_db = PostgresHook(postgres_conn_id=conn_id)
        conn = airflow_db.get_conn()
        cursor = conn.cursor()
        sql = "select count(*) from public.dag_run where dag_id = '{dag_id}' and state in ('running', 'queued', 'up_for_retry')".format(dag_id=dag_id)
        cursor.execute(sql)
        num_active_dagruns = cursor.fetchone()[0]
        return num_active_dagruns
    
    def is_latest_active_dagrun(**kwargs):
        num_active_dagruns = get_num_active_dagruns(dag_id=kwargs['dag'].dag_id)
        return (num_active_dagruns == 1)
    
    import datetime
    import time
    
    def bar(*args, **kwargs):
        t = datetime.datetime.now()
        execution_date = str(kwargs['execution_date'])
        with open("/home/airflow/test.log", "a") as myfile:
            myfile.write(execution_date + ' - ' + str(t) + '\n')
        time.sleep(90)
        with open("/home/airflow/test.log", "a") as myfile:
            myfile.write(execution_date + ' - ' + str(t) + ' +90\n')
        return 'bar: ok'