我在一天内有30个单独的任务,它们彼此之间没有依赖关系。这些任务运行相同的代码。唯一的区别是数据量,有些任务将在几秒钟内完成,有些任务将花费2个小时或更长时间。
问题在于追赶过程中,以秒为单位完成的任务被需要花费数小时才能完成的任务阻塞,然后才能转移到下一个执行日期。
我可以将它们分解为单个任务,但这似乎很愚蠢,将来有30项任务会越来越多。
是否可以在不同的执行时间在同一dag中运行任务?就像任务完成后一样,无论其他任务的执行情况如何,都将在下一个执行日期开始。
添加图片作为插图。基本上,我想在第一行看到另外两个绿色的方框,而第三行仍在后面。
编辑:
在y2k-shubham的explanation之后,我尝试实现它。但是它仍然无法正常工作。快速任务从2019-01-30 00
开始,在几秒钟内完成,由于慢速任务仍在运行,因此没有开始2019-01-30 01
。如果可能的话,最好并行运行2019-01-30 01
,2019-01-30 02
,2019-01-30 03
...
添加代码示例
import time
from datetime import datetime
from airflow import DAG
from airflow.operators.python_operator import PythonOperator
from airflow.utils.trigger_rule import TriggerRule
default_args = {
'owner': 'test',
'depends_on_past': False,
'start_date': datetime(2019, 1, 30, 0, 0, 0),
'trigger_rule': TriggerRule.DUMMY
}
dag = DAG(dag_id='test_dag', default_args=default_args, schedule_interval='@hourly')
def fast(**kwargs):
return 1
def slow(**kwargs):
time.sleep(600)
return 1
fast_task = PythonOperator(
task_id='fast',
python_callable=fast,
provide_context=True,
priority_weight=10000,
pool='fast_pool',
# weight_rule='upstream', # using 1.9, this param doesn't exist
dag=dag
)
slow_task = PythonOperator(
task_id='slow',
python_callable=slow,
provide_context=True,
priority_weight=500,
pool='slow_pool',
# weight_rule='upstream', # using 1.9, this param doesn't exist
dag=dag
)
fast_task >> slow_task # not working
答案 0 :(得分:1)
这可能是因为您执行的插槽少于慢的作业。调度程序并不特别在乎运行任务的顺序,因为您说过也不关心。
如果这对您确实很重要,则应将它们分解为不同的中断,或者应声明依赖项,以使较便宜的任务先完成。表达您想要的东西有多种方法,您只需要弄清楚那是什么。
答案 1 :(得分:1)
我可以为您的困境想出3种解决方案(当他们想到时会添加更多选择)
在start_date
(除task
本身的DAG
之外的各个start_date
上设置 DAG
),如here所述。但是,我绝不赞成这种方法,因为这就像退回到Airflow
尝试的基于时间的克朗替换。
使用pool
s按运行时/优先级隔离task
。这是一个想法(您可能需要根据需要进行重做):将所有微小的task
放在tiny_task_pool
中,而所有 big 都放在{ {1}}。让big_task_pool
的{{1}}数量比tiny_task_pool
显着更多。这将使您的微小任务中的starvation的可能性大大降低。您甚至可以在slot
个级别中发挥创意。
即使您的big_task_pool
之间没有真正的依赖关系,故意引入一些依赖关系也不会造成太大的伤害。 (或大多数)大任务由{em>小任务组成pool
(因此改变了task
的结构)。这将成为一种最短工作优先的方法。您还可以探索priority_weight
/ priority_rule
以获得更细粒度的控制。
以上所有替代方法都假定downstream
的长度(执行时间)是事先已知的。在现实世界中,可能并非如此。甚至可能会随着时间的推移逐渐变化。为此,我建议您调整您的 dag定义脚本 ,以将DAG
的平均(或中位数)运行时间算入过去'n'决定他们的优先级。
task
方法,只需向在先前运行中运行时间更长的task
提供稍后的start_date
(实际上是相同的日期,以后的时间)start_date
的方法,请根据其先前的运行持续时间在不同的task
周围移动pool
task
的{{1}}的时间。这听起来可能很困难,但是您可以像这样可视化:创建3个pool
并将它们链接起来(一个接一个)。现在,您必须填写前两个task
之间的所有小任务,以及接下来的两个{1>}之间的大任务。答案 2 :(得分:0)
结果是,可以设置两个变量,这将很容易解决我的问题。
concurrency
和max_active_runs
在下面的示例中,您可以运行4个dag,每个dag可以同时运行4个任务。其他组合也是可能的。
dag = DAG(
dag_id='sample_dag',
default_args=default_args,
schedule_interval='@daily',
# this will allow up to 16 tasks to be run at the same time
concurrency=16,
# this will allow up to 4 dags to be run at the same time
max_active_runs=4,
)