run命令运行过程
读取dag文件生成task依赖关系,然后生成封装airflow run的command命令,通过celery发送到executor端,重新执行该airflow run命令。
scheduler命令运行过程:
调度器通过SchedulerJob类run方法执行整个流程,包括使用多进程处理DagDir,包括生成Dag,产生DagRun,每个DagRun下又生成多个TaskInstance,然后将任务通过Executor分发到执行节点运行。涉及到的方法有:SchedulerJob类create_dag_run创建DagRun,DagRun类verify_integrity生成TaskInstance,任务封装为command命令后发送到执行节点,执行节点通过airflow run命令执行该command,此时Job类型为LocalTaskJob
数据库表关系:
dag_run表通过execution_date和task_instance关联
task_instance通过job_id和job表关联
通过airflow run命令观察整个流程
cli.py的run函数
关键语句dag = get_dag(args),根据dag_id获取dag实例
进入get_dag函数,关键语句dagbag = DagBag(process_subdir(args.subdir))
进入DagBag类__init__函数,关键语句self.collect_dags(dag_folder)
进入collect_dags函数,关键语句self.process_file(dag_folder, only_if_updated=only_if_updated)
进入process_file函数,关键语句
m = imp.load_source(mod_name, filepath) //filepath:DagDir目录下的一个Dag文件,假设为test.py
通过该语句test.py会被导入,语句被执行。在语句被执行时,比如test.py中有操作为:run_this_last = DummyOperator(task_id='run_this_last', dag=dag),在基类BaseOperator的__init__函数中存在语句self.dag = dag,进而调用dag的setter方法,DummyOperator的实例被添加到该dag实例中。
所有的dag被保存在一个字典中。
task = dag.get_task(task_id=args.task_id),所有task的实例已经被添加到dag实例的字典中
_run(args, dag, ti)
进入_run函数,我们查看else项针对远程执行任务的分支。关键语句
executor = GetDefaultExecutor() //获取executor的实例
executor.start()
executor.queue_task_instance(
ti,
mark_success=args.mark_success,
pickle_id=pickle_id,
ignore_all_deps=args.ignore_all_dependencies,
ignore_depends_on_past=args.ignore_depends_on_past,
ignore_task_deps=args.ignore_dependencies,
ignore_ti_state=args.force,
pool=args.pool)
executor.heartbeat() //将命令队列中的命令拿出来调用executor的execute_async方法发送过去,然后同步等结果
executor.end()
进入queue_task_instance函数,此处是CeleryExcutor类的实例,基类BaseExecutor
command = task_instance.command(
local=True,
mark_success=mark_success,
ignore_all_deps=ignore_all_deps,
ignore_depends_on_past=ignore_depends_on_past,
ignore_task_deps=ignore_task_deps,
ignore_ti_state=ignore_ti_state,
pool=pool,
pickle_id=pickle_id,
cfg_path=cfg_path)
self.queue_command( //将command放入队列
task_instance,
command,
priority=task_instance.task.priority_weight_total,
queue=task_instance.task.queue)
再次进入command函数,我们发现它依次调用了command_as_list、TaskInstance.generate_command
iso = execution_date.isoformat()
cmd = ["airflow", "run", str(dag_id), str(task_id), str(iso)]
cmd.extend(["--mark_success"]) if mark_success else None
cmd.extend(["--pickle", str(pickle_id)]) if pickle_id else None
cmd.extend(["--job_id", str(job_id)]) if job_id else None
cmd.extend(["-A"]) if ignore_all_deps else None
cmd.extend(["-i"]) if ignore_task_deps else None
cmd.extend(["-I"]) if ignore_depends_on_past else None
cmd.extend(["--force"]) if ignore_ti_state else None
cmd.extend(["--local"]) if local else None
cmd.extend(["--pool", pool]) if pool else None
cmd.extend(["--raw"]) if raw else None
cmd.extend(["-sd", file_path]) if file_path else None
cmd.extend(["--cfg_path", cfg_path]) if cfg_path else None
return cmd
结果就是:服务端发送一个airflow run命令到executor,然后通过Celery执行shell命令,命令内容就是上面的cmd结果。然后executor端会重新执行一遍airflow run命令。
整个流程结束