luigi适合静态、简单依赖且无需web ui或多用户权限的场景,如每日串行etl;它是轻量python库,无后台进程,本地调试快,但不支持动态dag和内置重试。

Luigi 适合什么场景
当你的任务流是静态的、依赖关系简单、且不需要 Web UI 或多用户权限管理时,Luigi 是更轻的落地选择。它本质是个 Python 库,不是服务,跑完就退出,没有后台常驻进程。
- 典型用例:每日 ETL 脚本串行执行(比如
download_data→clean_csv→load_to_db) - 依赖靠 Python 类继承和
requires()方法声明,写起来直接,但不支持运行时动态生成 DAG - 本地调试极快——改完代码直接
python my_pipeline.py,不用启服务、等调度器心跳 - 不处理任务重试的语义细节:
run()抛异常就失败,重试得自己在方法里加try/except和计数逻辑
Airflow 的“轻量”其实是假象
哪怕只跑一个 BashOperator,你也得先装 airflow、初始化数据库、启 airflow webserver 和 airflow scheduler 两个后台进程。这不是“用不用”的问题,是“绕不开”的基础设施成本。
-
airflow db init失败?大概率是没配好AIRFLOW_HOME或 SQLite 权限不对 - 想跳过 UI 直接触发?得用
airflow dags trigger命令,但前提是 scheduler 已在运行且心跳正常 - DAG 文件被扫描到但没出现在 UI 上?检查文件名是否含非法字符、
dag = DAG(...)是否在模块顶层、以及schedule_interval是否设为None(手动触发需显式设置) - 本地开发时用
SequentialExecutor看似轻量,但一旦切到LocalExecutor就要面对临时目录清理、子进程僵尸化等问题
参数和错误表现差异明显
同样一个“任务失败”,Luigi 和 Airflow 给你的反馈路径完全不同:前者靠日志和 Python traceback,后者得查 Web UI 的 Task Instance 日志页,再点进对应 worker 的日志文件。
-
Luigi报错常见于:RuntimeError: Task MyTask() is missing its requires()—— 意味着requires()返回了空列表或 None,但下游任务实际需要输入 -
Airflow报错常见于:Broken DAG: No module named 'my_module'—— DAG 文件 import 失败,路径没加进PYTHONPATH,或用了相对导入 -
Luigi的Parameter是类属性,类型校验弱;Airflow的default_args是字典,start_date必须是datetime对象,传字符串会静默失败 - 两者都支持环境变量注入,但
Luigi用luigi.configuration.get_config().get('core', 'local_scheduler'),Airflow用os.environ.get('AIRFLOW_VAR_MY_KEY'),混用容易漏配置
真要轻量,别选框架
如果只是几个脚本按顺序跑、失败后发个钉钉通知、每天凌晨两点执行,crontab + 一个带重试的 shell 脚本,比任何框架都可靠。加一层调度框架,等于主动引入状态存储、心跳超时、元数据锁、序列化兼容性这些你本来不需要操心的问题。
立即学习“Python免费学习笔记(深入)”;
非要用 Python 写调度逻辑,schedule 库(不是 APScheduler)几行就能搞定定时,配合 subprocess.run(..., check=True) 做串行调用,出错直接 raise,日志全在终端里——没有 Web UI,也没有 DAG 解析失败的困惑。
真正卡住人的从来不是语法,是当你发现 Luigi 的 LocalScheduler 在并发任务下会丢状态,或者 Airflow 的 trigger_dag 在 CeleryExecutor 下要等 30 秒才响应时,才意识到:轻量不是删功能,而是从一开始就不让那些功能存在。










