导入模块
# 导入所需的模块
# DAG用来实例化DAG对象,注意仅仅只是定义了一个对象,而不是进行真正的数据处理流程
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from datetime import datetime, timedelta
设置默认参数
在我们创建任务的时候我们可以使用这些默认参数
default_args = {
'owner': 'airflow',
'depends_on_past': False,
'start_date': datetime(2015, 6, 1),
'email': ['airflow@example.com'],
'email_on_failure': False,
'email_on_retry': False,
'retries': 1,
'retry_delay': timedelta(minutes=5),
# 'queue': 'bash_queue',
# 'pool': 'backfill',
# 'priority_weight': 10,
# 'end_date': datetime(2016, 1, 1),
}
实例化一个DAG
我们需要一个 DAG 对象来嵌入我们的任务,下面的代码中,我们首先定义一个字符串,作为DAG的唯一标识,然后传入默认的参数字典(上面定义的),然后定义调度的间隔为1天
dag = DAG(
'tutorial', default_args=default_args, schedule_interval=timedelta(days=1))
任务
实例化 operator 时会生成任务。一个从 operator 实例化的对象也称为构造器(constructor),第一个参数 task_id
作为任务的唯一标识
t1 = BashOperator(
task_id='print_date',
bash_command='date',
dag=dag)
t2 = BashOperator(
task_id='sleep',
bash_command='sleep 5',
retries=3,
dag=dag)
注意我们如何将各个Operator特定的参数(bash_command) 以及继承自BaseOperator的所有Operator的通用参数(retries) 传递给Operator的constructor。这比将每个参数传递给每个constructor要简单。当然我们也注意到,t2继承的通用参数retries被我们重载,赋值成3了。
任务的前提规则如下:
- 明确传递参数
- 值在default_args字典中存在
- operator的默认值(如果存在)
一个任务必须包含或者继承参数 task_id 与 owner ,否则Airflow 将会抛出异常
Templating with Jinja
Airflow利用Jinja Templating的强大功能,为管道作者提供一组内置参数和宏。Airflow还为管道作者提供了定义自己的参数,宏和模板的钩子(Hooks)。
本教程几乎没有涉及在Airflow中使用模板进行操作,本节的目的是让您了解此功能的存在,让您熟悉双花括号和最常见的模板变量:{{ds}}(今天的“日期戳”)。
templated_command = """
{% for i in range(5) %}
echo "{{ ds }}"
echo "{{ macros.ds_add(ds, 7) }}"
echo "{{ params.my_param }}"
{% endfor %}
"""
t3 = BashOperator(
task_id='templated',
bash_command=templated_command,
params={'my_param': 'Parameter I passed in'},
dag=dag)
请注意,templated_command包含{%%}
块中的代码逻辑,引用参数如{{ds}}
,调用{{macros.ds_add(ds,7)}
}中的函数,并在{{params.my_param}}
中引用用户定义的参数。
BaseOperator中的params hook允许您将参数和/或对象的字典传递给模板。
请花点时间了解参数my_param如何通过模板。
文件也可以传递给bash_command
参数,例如bash_command ='templated_command.sh'
,其中文件位置相对于包含管道文件的目录(在本例中为tutorial.py)。
这可能有许多种原因,例如分离脚本的逻辑和管道代码,允许在用不同语言编写的文件中执行正确的代码突出显示,以及构造管道的通用性及灵活性。
也可以将template_searchpath
定义为指向DAG构造函数调用中的任何文件夹位置。
使用相同的DAG构造函数调用,可以定义user_defined_macros
,它允许您指定自己的变量。
例如,将dict(foo ='bar')
传递给此参数允许您在模板中使用{{foo}}
。
此外,指定user_defined_filters
允许您注册自己的过滤器。
例如,将dict(hello = lambda name:'Hello%s'%name)
传递给此参将允许您在自己的模板中使用{{'world'|{{ 'world' | hello }}
有关自定义过滤器的更多信息,请查看Jinja文档
关于可在模板中引用的变量和宏的更多信息,请务必阅读宏参考
设置依赖关系
我们有互不依赖的三个任务 t1,t2,t3。接下来有一些定义它们之间依赖关系的方法
t1.set_downstream(t2)
# 这个表示t2将依赖于t1
# 等价于
t2.set_upstream(t1)
# 位移运算符也可以完成 t2依赖于t1 的设置
t1 >> t2
# 位移运算符完成 t1依赖于t2 的设置
t2 << t1
# 使用位移运算符更加简洁地设置多个连锁依赖关系
t1 >> t2 >> t3
# 任务列表也可以被设置成依赖,以下几种表达方式是等效的
t1.set_downstream([t2, t3])
t1 >> [t2, t3]
[t2, t3] << t1
请注意,在执行脚本时,Airflow会在DAG中找到循环或多次引用依赖项时引发异常。
简要重述以上内容
我们已经有了十分基础的 DAG 了,你的代码应当看起来和下面给出的差不多
"""
Code that goes along with the Airflow tutorial located at:
https://github.com/apache/airflow/blob/master/airflow/example_dags/tutorial.py
"""
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from datetime import datetime, timedelta
default_args = {
'owner': 'airflow',
'depends_on_past': False,
'start_date': datetime(2015, 6, 1),
'email': ['airflow@example.com'],
'email_on_failure': False,
'email_on_retry': False,
'retries': 1,
'retry_delay': timedelta(minutes=5),
# 'queue': 'bash_queue',
# 'pool': 'backfill',
# 'priority_weight': 10,
# 'end_date': datetime(2016, 1, 1),
}
dag = DAG(
'tutorial', default_args=default_args, schedule_interval=timedelta(days=1))
# t1, t2 and t3 are examples of tasks created by instantiating operators
t1 = BashOperator(
task_id='print_date',
bash_command='date',
dag=dag)
t2 = BashOperator(
task_id='sleep',
bash_command='sleep 5',
retries=3,
dag=dag)
templated_command = """
{% for i in range(5) %}
echo "{{ ds }}"
echo "{{ macros.ds_add(ds, 7)}}"
echo "{{ params.my_param }}"
{% endfor %}
"""
t3 = BashOperator(
task_id='templated',
bash_command=templated_command,
params={'my_param': 'Parameter I passed in'},
dag=dag)
t2.set_upstream(t1)
t3.set_upstream(t1)
测试
运行脚本
是时候进行一些测试了,我们先确保管道解析成功。
首先确认上述的代码已经存入tutorial.py
,文件的位置位于你的airflow.cfg
指定的 dags
文件夹内,你的DAGs文件夹默认在~/airflow/dags
在命令行执行:
python ~/airflow/dags/tutorial.py
如果这个脚本不抛出异常,则意味着你没有犯任何可怕的错误,而且你的Airflow环境还不错。
命令行元数据验证
让我们运行一些命令来进一步验证上一个脚本
# 打印激活的DAGs 的列表
airflow list_dags
# 打印dag_id 为 "tutorial" 的任务的列表
airflow list_tasks tutorial
# 打印 tutorial DAG中任务的层级关系
airflow list_tasks tutorial --tree
测试
让我们通过在特定日期运行实际任务实例来进行测试。
在此上下文中指定的日期是execution_date
,它模拟特定日期+时间调度运行任务或dag:
# command layout: command subcommand dag_id task_id date
# testing print_date
airflow test tutorial print_date 2015-06-01
# testing sleep
airflow test tutorial sleep 2015-06-01
现在还记得我们之前用模板做过的事吗?
通过运行此命令,了解如何呈现和执行此模板:
# testing templated
airflow test tutorial templated 2015-06-01
这应该会显示详细的事件日志并最终运行bash命令并打印结果
请注意,airflow test
命令在本地运行任务实例,将其日志输出到stdout(在屏幕上),不依赖于依赖项,并且不向数据库传达状态(运行,成功,失败,...)。
它只允许测试单个任务实例。
backfill
一切看起来都运行良好,让我们运行backfill。
backfill将遵守您的依赖关系,将日志发送到文件并与数据库通信以记录状态。如果您有网络服务器,您还可以跟踪进度。如果您有兴趣在backfill过程中直观地跟踪进度,airflow webserver
将启动Web服务器。
请注意,如果使用depends_on_past = True
,则单个任务实例将取决于前面任务实例的成功。但是如果指定了这个任务的start_date,此依赖关系将被忽略。
backfill: 在指定的日期范围内运行DAG的子部分。
如果使用reset_dag_run
选项,则backfill
将首先提示用户airflow
是否应清除backfill
日期范围内的所有先前dag_run
和task_instances
。
如果使用rerun_failed_tasks
,则backfill
将自动重新运行backfill
日期范围内的先前失败的任务实例。
``cmd
airflow backfill [-h] [-t TASK_REGEX] [-s START_DATE] [-e END_DATE] [-m] [-l]
[-x] [-i] [-I] [-sd SUBDIR] [--pool POOL]
[--delay_on_limit DELAY_ON_LIMIT] [-dr] [-v] [-c CONF]
[--reset_dagruns] [--rerun_failed_tasks] [-B]
dag_id
```
此上下文中的日期范围是start_date和可选的end_date,它们用于使用此dag中的任务实例填充运行计划。
# 可选,在后台开启一个web服务器
# airflow webserver --debug &
# 在一个时间范围内开始你的 backfill
airflow backfill tutorial -s 2015-06-01 -e 2015-06-07