Airflow中通过Python运行bash脚本返回0却无输出文件是什么原因
核心问题分析
你遇到的无报错但无输出文件的核心原因是shell命令的错误被吞、相对路径匹配异常、权限不足这三类,具体排查点如下:
- shell命令的返回码默认只取最后一条主命令的执行结果:你写的
pg_dump xxx > 输出文件逻辑里,哪怕重定向写入失败(比如路径不存在、无写入权限),只要pg_dump本身执行完成,shell返回码都可能是0,所以Airflow任务显示执行成功。 - 相对路径不匹配Airflow的执行上下文:你代码里所有用
dags/xxx的相对路径,都是相对于Airflow worker进程的工作目录(默认是$AIRFLOW_HOME),不是你DAG文件所在的目录,要么读不到shell脚本,要么输出的文件写到了你没预期的目录下。 - 字节类型兼容问题:你用
rb模式读取shell脚本得到的是bytes字节流,直接传给subprocess在部分Python版本/操作系统环境下会出现执行异常但不报错的问题。 - 环境变量不匹配:Airflow worker进程的PATH环境变量可能没有包含pg_dump的安装路径,导致pg_dump执行异常但错误没有输出。
- 权限不足:Airflow默认用
airflow用户运行worker进程,该用户如果对你的输出目录、shell脚本文件没有读写权限,也会导致写入/执行失败。
修复步骤
所有路径替换为绝对路径
读取shell脚本时用DAG文件所在目录拼接绝对路径,避免工作目录差异:import os def running_dump(): # 获取当前DAG文件所在目录的绝对路径 dag_dir = os.path.dirname(os.path.abspath(__file__)) shell_path = os.path.join(dag_dir, 'scripts/shell_scripts/daily_pg_dump.sh') with open(shell_path, 'r', encoding='utf-8') as file: script = file.read() # 输出路径也改成绝对路径,提前判断输出目录是否存在,不存在则创建 output_dir = os.path.join(dag_dir, 'data_bucket') os.makedirs(output_dir, exist_ok=True)对应shell脚本里的输出路径也改成绝对路径,同时pg_dump写全路径(可以在服务器执行
which pg_dump获取实际路径,比如/usr/local/bin/pg_dump),开头加set -euo pipefail确保任意一步执行失败都会返回非0错误码,不会吞异常:set -euo pipefail PGPASSWORD='*******' /usr/local/bin/pg_dump -h ***** -p ***** -U ***** -d * -t table_1 > /你的DAG目录绝对路径/dags/data_bucket/table_1_backup.sql优化subprocess调用逻辑,捕获错误日志
替换subprocess.call为subprocess.run,开启参数主动抛出异常并打印错误日志:import subprocess def running_dump(): # 前面的路径读取逻辑不变 result = subprocess.run( script, shell=True, check=True, # 执行失败直接抛异常 capture_output=True, text=True ) # 打印日志到Airflow任务日志方便排查 print("执行标准输出:", result.stdout) print("执行错误输出:", result.stderr)校验权限配置
确认airflow用户对shell脚本有读权限、对输出目录有读写权限,可执行以下命令临时测试:sudo chmod +r /你的shell脚本绝对路径/daily_pg_dump.sh sudo chown -R airflow:airflow /你的输出目录绝对路径/data_bucket
内容的提问来源于stack exchange,提问作者Shadow Walker
相关产品推荐
相关产品推荐

