1. airflow官方教程——一个简单案例

做一个官方教程的搬运工,纯粹为了自己过一遍脑子。

1.工作流定义示例

下面是定义工作流的示例代码:

"""
Code that goes along with the Airflow tutorial located at:
https://github.com/airbnb/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)

# 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)

这个Airflow Python脚本实际上只是一个配置文件,将DAG的结构指定为代码。这里定义的实际任务将在与此脚本上下文不同的上下文中运行。不同的任务在不同的时间点上运行在不同的工人身上,这意味着这个脚本不能用于任务之间的交叉通信。请注意,出于这个目的,我们有一个更高级的特性称为 XCOM
人们有时会认为DAG定义文件是他们可以进行一些实际数据处理的地方——事实并非如此!脚本的目的是定义DAG对象。它需要快速评估(秒,而不是分钟),因为调度程序将定期执行它,以反映任何更改(如果有的话)。

2.示例代码分析

(1)导入模块

一个 Airflow 工作流是一个定义 Airflow DAG的python脚本 ,我们从引入模块开始。

# The DAG object; we'll need this to instantiate a DAG
from airflow import DAG

# Operators; we need this to operate!
from airflow.operators.bash_operator import BashOperator

(2)默认参数

我们即将创建一个DAG和一些任务,我们可以选择将一组参数显式地传递给每个任务的构造函数(这将变得多余),或者(更好!)。
我们可以定义一个默认参数字典,我们可以在创建任务时使用这些参数。

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),
}

关于基本参数和它们的作用请参考文档:py:class:airflow.models.BaseOperator

另外,请注意,您可以很容易地定义不同的参数集,这些参数集将服务于不同的目的。这方面的一个例子是在生产环境和开发环境之间设置不同的设置。

(3)实例化一个DAG

我们需要一个DAG对象来嵌套我们的任务。在这里,我们传递一个字符串,它定义了 dag_id,它作为DAG的唯一标识符。我们还传递我们刚刚定义的默认参数字典,并为DAG定义一个调度间隔schedule_interval为1天。

dag = DAG(
    'tutorial', default_args=default_args, schedule_interval=timedelta(1))

(4)任务

任务在实例化运算符对象时生成。从操作符实例化的对象称为构造函数。第一个参数 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)

请注意,我们如何将操作符特定的参数(bash_command)和从BaseOperator继承的所有操作符(retries)共有的参数传递给操作符的构造函数。这比为每个构造函数调用传递每个参数更简单。另外,请注意,在第二个任务中,我们给retries参数重新赋值为3

任务的优先级规则如下:

  1. 显式传递默认参数
  2. default_args 中已经设置好的参数
  3. 操作的默认值

一个任务必须包括或继承参数task_idowner,否则将引发Airflow异常。

(5)Jinja模板

airflow利用了Jinja模板的力量,并为工作流作者提供了一组内置参数和宏。airflow还为工作流作者提供接口来定义他们自己的参数、宏和模板。
本教程仅仅触及了在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接口允许将参数和/或对象的字典传递给模板。请花时间了解参数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’| hello }}。有关自定义过滤器的更多信息,请参阅Jinja文档

有关可以在模板中引用的变量和宏的更多信息,请确保通过节读取。

(6)设置依赖

我们有两个不相互依赖的简单任务。以下是定义它们之间的依赖关系的几种方法:

t2.set_upstream(t1)

# This means that t2 will depend on t1
# running successfully to run
# It is equivalent to
# t1.set_downstream(t2)

t3.set_upstream(t1)

# all of this is equivalent to
# dag.set_dependency('print_date', 'sleep')
# dag.set_dependency('print_date', 'templated')

请注意,在执行脚本时,当ailflow在DAG中找到循环或当依赖项被引用不止一次时,会引发异常。

(7)概括

到目前为止,我们有一个非常基本的DAG。此时,你的代码应该如下所示:

"""
Code that goes along with the Airflow located at:
http://airflow.readthedocs.org/en/latest/tutorial.html
"""
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(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)

(8)测试

1)执行脚本

是时候做些测试了。首先,让我们确保工作流解析。假设我们是在你的airflow.cfg中引用的DAGS文件夹中的tutorial.py中保存了上一步的代码。DAG的默认位置是~/airflow/dags

python ~/airflow/dags/tutorial.py

如果脚本没有引发异常,这意味着没有任何严重的错误,你的的airflow环境是健全的。

2)命令行元数据验证

让我们运行一些命令来进一步验证这个脚本。

# print the list of active DAGs
airflow list_dags

# prints the list of tasks the "tutorial" dag_id
airflow list_tasks tutorial

# prints the hierarchy of tasks in the tutorial DAG
airflow list_tasks tutorial --tree

3)测试

让我们通过在特定日期上运行任务实例来进行测试。在此上下文中指定日期的是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(屏幕上),不需要依赖项,也不同步状态(运行、成功、失败、…)到数据库。它只允许测试单个任务实例。

4)回填(Backfill)

一切看起来都很好,所以让我们运行一个回填。backfill将尊重您的依赖关系,将日志发送到文件中,并与数据库对话以记录状态。如果你启动了web服务,你将能够跟踪进度。airflow webserver服务将启动一个Web服务器,如果你有兴趣跟踪进度,并查看可视化回填进展。

请注意,如果使用depends_on_past=True,则单独的任务实例将依赖于前一个任务实例的成功,除了指定的start_date日期之外,它对此依赖性不予理会。

此上下文中的日期范围是start_date和可选的end_date,用于对此DAG中的任务实例填充运行计划。

# optional, start a web server in debug mode in the background
# airflow webserver --debug &

# start your backfill on a date range
airflow backfill tutorial -s 2015-06-01 -e 2015-06-07
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,423评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,339评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,241评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,503评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,824评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,262评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,615评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,337评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,989评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,300评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,829评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,193评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,753评论 3 230
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,970评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,708评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,295评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,207评论 2 258

推荐阅读更多精彩内容

  • 本文将介绍 Airflow 这一款优秀的调度工具。主要包括 Airflow 的服务构成、Airflow 的 Web...
    a7f00a9019ae阅读 60,993评论 6 42
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,083评论 18 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,465评论 6 13
  • 望月如你 前世情 冰雪覆面 踏月行 漫天星辰 不比你 如玲珑兮 情亦浓
    日落吟晨阅读 418评论 0 0
  • 你我二十多年的兄妹,大小故事应该是数不胜数,但记忆装不下这么长的时间,仔细想想,也就只剩几天的故事梗概——话说来矛...
    笑浪荡阅读 521评论 0 0