1. 什么是退出码(Exit Code)?
退出码(Exit Code)是程序执行结束后返回的一个 整数值,表示任务的执行结果:
- 0(成功):任务执行正常,Airflow 认为任务状态为
success
。 - 非 0(失败):任务执行异常,Airflow 认为任务状态为
failed
,并可能触发重试或失败回调。
2. Airflow 如何检查退出码
Airflow 在任务执行结束后,会检查任务对应的进程或子进程的退出码:
- Scheduler 通过 Executor(如 LocalExecutor、CeleryExecutor、KubernetesExecutor)启动任务。
- 任务执行后,Executor 会捕获进程的
exit code
。 - 如果
exit code != 0
,则 Airflow 会将任务状态标记为failed
,并决定是否重试。
import sys
def my_task():
print("任务执行失败")
sys.exit(1) # 返回非零退出码,Airflow 认为任务失败
task = PythonOperator(
task_id="fail_task",
python_callable=my_task
)
3. 不同 Operator 的退出码处理
不同类型的 Operator 处理退出码的方式略有不同:
3.1 BashOperator
BashOperator 运行 shell
脚本,Airflow 直接使用 shell
命令的退出码:
from airflow.operators.bash import BashOperator
task = BashOperator(
task_id="fail_bash",
bash_command="exit 1" # 退出码 1,任务失败
)
- exit 0 → 任务
success
- exit 1 → 任务
failed
- exit 2 → 任务
failed
- exit 127 → 任务
failed
(通常表示命令未找到)
忽略失败
如果你希望忽略任务失败,可以使用 ignore_exit_code
:
task = BashOperator(
task_id="ignore_fail",
bash_command="exit 1",
ignore_exit_code=1 # 让 Airflow 认为任务成功
)
3.2 PythonOperator
PythonOperator 运行 Python 函数:
- 如果 函数执行正常返回,任务标记为
success
。 - 如果 函数抛出异常,任务标记为
failed
。 - 如果 显式调用
sys.exit(n)
,Airflow 读取退出码并决定任务状态。
from airflow.operators.python import PythonOperator
import sys
def fail_task():
raise Exception("任务失败") # 抛出异常,Airflow 任务失败
task = PythonOperator(
task_id="fail_python",
python_callable=fail_task
)
等价于:
def fail_task():
sys.exit(1) # 退出码 1,任务失败
3.3 DockerOperator
DockerOperator 运行 Docker 容器,Airflow 读取容器的退出状态:
from airflow.providers.docker.operators.docker import DockerOperator
task = DockerOperator(
task_id="docker_task",
image="my_image",
command="python script.py",
auto_remove=True
)
- 容器 正常退出(exit 0) → 任务
success
- 容器 异常退出(exit 1) → 任务
failed
exit 137
→ 通常表示 OOM(内存不足)exit 143
→ 任务超时被 SIGTERM 终止
3.4 KubernetesPodOperator
KubernetesPodOperator 运行 Kubernetes Pod,Airflow 读取 Pod 的退出状态:
from airflow.providers.cncf.kubernetes.operators.kubernetes_pod import KubernetesPodOperator
task = KubernetesPodOperator(
task_id="k8s_task",
name="my-pod",
image="python:3.8",
cmds=["python", "-c", "exit(1)"]
)
exit 0
→ 任务success
exit 1
→ 任务failed
exit 137
→ Pod 被 Killed,可能 OOMexit 143
→ Pod 被 Airflow 终止(超时)
4. 任务失败后 Airflow 的处理
当任务退出码非 0 时,Airflow 任务失败,接下来的处理方式可能是:
1. 重试任务(如果 retries > 0
)
2. 标记任务 failed(如果 retries == 0
)
3. 触发 on_failure_callback
4. 发送通知
5. 影响依赖任务
6. 记录失败日志到 Airflow 元数据库
5. 任务失败但不影响 DAG
如果你想让 任务失败但不影响 DAG 继续执行,可以使用:
(1) trigger_rule="all_done"
允许 DAG 继续执行:
task = BashOperator(
task_id="fail_task",
bash_command="exit 1",
trigger_rule="all_done" # 失败也会继续运行下游任务
)
(2) ignore_exit_code
task = BashOperator(
task_id="ignore_exit",
bash_command="exit 1",
ignore_exit_code=1 # 让 Airflow 认为任务成功
)
(3) allow_failure=True
适用于 KubernetesPodOperator:
task = KubernetesPodOperator(
task_id="k8s_task",
name="my-pod",
image="python:3.8",
cmds=["python", "-c", "exit(1)"],
allow_failure=True # 任务失败不影响 DAG
)
6. 总结
退出码 | 含义 |
---|---|
0 | 任务成功 (success) |
1 | 任务失败 (failed) |
127 | 命令未找到 |
137 | OOM 被杀死 |
143 | 任务超时被 SIGTERM 终止 |
exit 1 | 任务失败 |
exit 0 | 任务成功 |
Airflow 通过 检查进程的退出码 来判定任务是否执行成功。不同 Operator 对退出码的处理略有不同,但 0 表示成功,非 0 表示失败 是通用规则。如果需要忽略失败,可以使用 ignore_exit_code
或 trigger_rule
。
声明: 笔记源于个人学习总结,疏漏难免。若您发现描述有误,恳请留言斧正,共同进步。感恩相遇,望多包涵!