Dagu 2.21.0 配置参数详解

逐字段实测 Dagu 2.21.0 三层配置:DAG YAML(steps 依赖、retry_policy 真实重试、env/params、output 传递、handler_on 失败钩子、schedule、SMTP 邮件)、base.yaml 全局默认值、dagu.env 服务端变量。附生产配置模板、YAML 语法报错实测与 FAQ。

Dagu自动化监控2026/10/19

Dagu 2.21.0 配置参数详解

目标:逐字段讲透 Dagu 2.21.0 的三层配置——工作流定义 YAML(DAG 文件)、全局继承配置(base.yaml)、服务端环境变量(dagu.env),所有字段含义以官方 base.yaml 内置注释与实测行为为准,每个字段配实测回显。全文命令与回显均在 Ubuntu 22.04 + Dagu 2.21.0 环境逐条实测通过(含重试、失败钩子、邮件通知、调度识别等完整闭环)。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)。
  • Dagu 版本:2.21.0(dagu version 实测回显 2.21.0),systemd 服务托管(dagu.service)。
  • 数据目录:DAGU_HOME=/var/lib/dagu(dags/ 工作流、logs/ 日志、data/ 状态)。
  • 服务端配置:/etc/dagu/dagu.env(DAGU_HOST=0.0.0.0、DAGU_PORT=8114,安装默认端口 8080,本机 8080 已占用故改 8114)。
  • 全局配置:/var/lib/dagu/base.yaml(首次启动自动生成,含全量字段注释,是官方参数文档的可执行形态)。
  • 辅助实测组件:本地 SMTP 调试服务器(127.0.0.1:1025,捕获通知邮件)、本地 HTTP 接收器(127.0.0.1:1026,捕获 Webhook)。
  • CLI 约定:本文所有 CLI 命令均在 export DAGU_HOME=/var/lib/dagu 下执行,保证与服务端操作同一套工作流目录。

二、前置条件

  • 已按《Ubuntu 22.04 安装 Dagu 2.21.0 指南》完成安装,systemctl is-active dagu 为 active。
  • 确认配置三层各自的生效优先级(官方 base.yaml 头部注释原文):Precedence: global base -> workspace base -> DAG,即全局 base.yaml → 工作区 base.yaml → DAG 文件自身,下层覆盖上层同名键;DAG 的 env: 是追加而非替换全局 env。

三、参数查看与修改方式

三套配置各有查看入口,先建立全局认识再逐字段深入。

3.1 DAG 文件(一层一工作流)

位置 $DAGU_HOME/dags/*.yaml,一个文件一个工作流。列出已加载的工作流:

dagu ls

实测回显:

NAME
c1-fail-demo
c1-retry-demo
c1-schedule-demo
d2-check-demo
d2-webhook-demo
example-01-basic-sequential
example-02-parallel-execution
example-03-scheduling
example-04-nested-workflows
example-05-template-and-file
example-06-retry-on-failure

修改后无需重启服务:调度器监听文件变化,实测日志 msg="DAG added/updated" name=c1-retry-demo.yaml,保存即生效。

3.2 schema 子命令(内置字段文档)

Dagu 内置 schema 文档查询,不用翻网页:

dagu schema --help

实测回显(节选):

Display schema documentation for DAG or config

Usage:
  dagu schema [dag|config] [flags]

3.3 服务端环境变量(dagu.env)

systemd 单元通过 EnvironmentFile=/etc/dagu/dagu.env 注入,改后需 systemctl restart dagu。查看当前值:

cat /etc/dagu/dagu.env

实测回显:

DAGU_HOME=/var/lib/dagu
DAGU_HOST=0.0.0.0
DAGU_PORT=8114

3.4 修改方式小结

层文件生效方式
DAG 工作流$DAGU_HOME/dags/*.yaml保存即生效(文件监听)
全局继承$DAGU_HOME/base.yaml保存即生效(官方注释:Changes to global or workspace defaults are reloaded automatically)
服务端/etc/dagu/dagu.envsystemctl restart dagu

四、配置体系总览

先看一张「哪个诉求改哪层」的路标表,再进入字段详解:

诉求配置位置关键字段
某工作流的定时/步骤/重试/通知DAG 文件schedule、steps、retry_policy、handler_on
所有工作流共享的默认值base.yamltype、overlap_policy、hist_retention_days、smtp、mail_on
监听地址/端口/数据目录dagu.envDAGU_HOST、DAGU_PORT、DAGU_HOME

💡 技术拓展:定时调度里的 cron 表达式存在两派写法——标准 5 段(分 时 日 月 周,本文所用)与扩展 6/7 段(Quartz 系,含秒与年份)。Dagu 采用标准 5 段并支持 CRON_TZ=时区 前缀声明时区; Quartz 系(如某些 Java 调度器)字段更多但迁移时要删秒位。本文因与 crontab 迁移场景对齐,采用标准 5 段。

五、DAG YAML 核心字段详解

以下每个字段均来自实测 DAG 文件,YAML 直接决定执行行为。

5.1 steps 与 depends:步骤与依赖编排

steps 是 DAG 的主体,每个步骤用 id 标识、run 给 shell 命令、depends 声明依赖(单值或数组)。实测 DAG(保存为 $DAGU_HOME/dags/c1-retry-demo.yaml):

description: "C1 field test - deps retry env output"
type: graph

env:
  - APP_ENV: production
  - REPORT_DIR: /var/lib/dagu/reports

steps:
  - id: prepare
    run: echo "prepare env=$APP_ENV dir=$REPORT_DIR"
    output: PREP_MSG

  - id: flaky
    working_dir: ${context.paths.artifacts_dir}
    run: |
      if [ -f marker ]; then
        echo "flaky recovered, got: ${PREP_MSG}"
      else
        touch marker
        echo "simulated transient failure"
        exit 1
      fi
    depends: [prepare]
    retry_policy:
      limit: 3
      interval_sec: 2

  - id: finish
    run: echo "workflow done"
    depends: [flaky]

逐项说明:type: graph 按依赖图调度(无依赖步骤并行),type: chain 则严格按定义顺序串行;run 支持多行块标量(整段脚本);output: PREP_MSG 把步骤 stdout 捕获进变量,后续步骤用 ${PREP_MSG} 引用;working_dir 指定步骤工作目录,${context.paths.artifacts_dir} 是本次运行的产物目录(每次运行独立,天然隔离临时文件);depends: [prepare] 写成 depends: prepare 等价。

执行前先静态校验与干跑:

dagu validate /var/lib/dagu/dags/c1-retry-demo.yaml
dagu dry /var/lib/dagu/dags/c1-retry-demo.yaml

实测回显(dry):

time=2026-10-19T05:06:47.397Z level=INFO msg="Step started" dag=c1-retry-demo run-id=034iRmy23vJKhb3wcB6jcK step=prepare
time=2026-10-19T05:06:47.402Z level=INFO msg="Step started" dag=c1-retry-demo run-id=034iRmy23vJKhb3wcB6jcK step=flaky
time=2026-10-19T05:06:47.402Z level=INFO msg="Step started" dag=c1-retry-demo run-id=034iRmy23vJKhb3wcB6jcK step=finish
time=2026-10-19T05:06:47.403Z level=INFO msg="Dry-run completed" dag=c1-retry-demo run-id=034iRmy23vJKhb3wcB6jcK params=[]
Succeeded - 2026-10-19T05:06:47Z

dag: c1-retry-demo (0s)
├─log: /var/lib/dagu/logs/c1-retry-demo/dag-run_20261019_050647Z_034iRmy23vJKhb3wcB6jcK/dag-run_20261019.050647.396.034iRmy2.log
│
├─prepare [succeeded]
│ └─echo "prepare env=$APP_ENV dir=$REPORT_DIR"
│
├─flaky [succeeded]
│
└─finish [succeeded]
  └─echo "workflow done"

Result: Succeeded

真实执行:

dagu start /var/lib/dagu/dags/c1-retry-demo.yaml

实测回显:

Succeeded - 2026-10-19T05:06:53Z

dag: c1-retry-demo (2.0s)
├─log: /var/lib/dagu/logs/c1-retry-demo/dag-run_20261019_050653Z_034iRn7eRdvuJNPbziddBy/dag-run_20261019.050653.517.034iRn7e.log
│
├─prepare (0s) [succeeded]
│ ├─echo "prepare env=$APP_ENV dir=$REPORT_DIR"
│ │
│ └─stdout: /var/lib/dagu/logs/c1-retry-demo/dag-run_20261019_050653Z_034iRn7eRdvuJNPbziddBy/run_20261019_050653Z_22fd17/prepare.20261019.050653.527.034iRn7e.out
│     prepare env=production dir=/var/lib/dagu/reports
│
├─flaky (2.0s) [succeeded]
│ └─stdout: /var/lib/dagu/logs/c1-retry-demo/dag-run_20261019_050653Z_034iRn7eRdvuJNPbziddBy/run_20261019_050653Z_22fd17/flaky.20261019.050653.533.034iRn7e.out
│     simulated transient failure
│     flaky recovered, got: prepare env=production dir=/var/lib/dagu/reports
│
└─finish (0s) [succeeded]
  ├─echo "workflow done"
  │
  └─stdout: /var/lib/dagu/logs/c1-retry-demo/dag-run_20261019_050653Z_034iRn7eRdvuJNPbziddBy/run_20261019_050653Z_22fd17/finish.20261019.050655.541.034iRn7e.out
      workflow done

Result: Succeeded

三个关键行为全部验证:env 变量在步骤中展开(env=production dir=/var/lib/dagu/reports);flaky 首次失败后自动重试成功(总耗时 2.0s = interval_sec 的重试间隔);output 变量 PREP_MSG 跨步骤传递(重试输出里带出了 prepare 的完整回显)。

5.2 retry_policy:重试策略

步骤级字段,继承自全局 defaults.retry_policy(见第六章)。已实测字段:

字段实测值含义
limit3最大重试次数
interval_sec2重试间隔秒数;backoff: true 时按指数倍增(next = interval × backoff^attempt),max_interval_sec 封顶
exit_code未测(默认全部失败码重试)仅对指定退出码重试,如 [1, 2]

失败与重试在日志里的原始记录($DAGU_HOME/logs/c1-retry-demo/dag-run_*/dag-run_*.log):

time=2026-10-19T05:06:53.537Z level=INFO msg="Step execution failed; retrying" step=flaky err="exit status 1" retry=0 exit-code=1

日志目录布局(stdout 与 stderr 分离,默认 log_output: separate):

dag-run_20261019_050653Z_034iRn7eRdvuJNPbziddBy/
├── dag-run_20261019.050653.517.034iRn7e.log    # DAG 级执行日志(调度/重试记录)
└── run_20261019_050653Z_22fd17/
    ├── prepare.20261019.050653.527.034iRn7e.out
    ├── prepare.20261019.050653.527.034iRn7e.err
    ├── flaky.20261019.050653.533.034iRn7e.out
    └── finish.20261019.050655.541.034iRn7e.out

💡 技术拓展:失败重试有两种粒度——步骤级(本文所用 retry_policy,只重跑失败步骤)与 DAG 级(base.yaml 注释中的 retry_policy: {limit, interval_sec},失败后整个 DAG 换新 run-ID 重跑,官方注释明确默认关闭因为工作流可能有非幂等副作用)。另有运行后手动重试:UI 的 retry 按钮与 dagu retry 子命令(同 run-ID 重放)。本文步骤用幂等的 marker 文件演示,实际采用步骤级重试,粒度细、影响面小。

5.3 schedule:定时调度

description: "C1 schedule test - daily 03:00"
schedule: "0 3 * * *"
steps:
  - id: job
    run: echo "daily job running"

实测回显(保存后 API 视角的调度识别,UI 列表页同源数据):

{"dag":{"name":"c1-schedule-demo","schedule":[{"expression":"0 3 * * *","kind":"cron"}],...},"latestDAGRun":{"status":"not_started"}}

写法要点:多时段用数组 schedule: ["0 2 * * *", "0 12 * * *"];带时区写 schedule: "CRON_TZ=Asia/Shanghai 0 3 * * *";配合 base.yaml 的 catchup_window: "6h",调度器重启后 6 小时内错过的 cron 间隔会自动补跑(官方注释:max 1000)。overlap_policy: skip(默认)表示上一轮未结束时新触发放弃;all 排队、latest 只保留最新。

5.4 env 与 params:环境变量与运行参数

env 是静态环境变量(实测见 5.1);params 是可运行时覆盖的参数,支持 JSON Schema 校验(官方示例 example-03 原文):

params:
  - name: environment
    type: string
    enum: [dev, staging, prod]
    default: staging
    description: Target environment for this run
  - name: batch_size
    type: integer
    minimum: 1
    maximum: 1000
    default: 100
    description: Number of records to process

env:
  - LOG_LEVEL: info

steps:
  - id: plan
    run: echo "Planning ${params.batch_size} records for ${params.environment}"

引用语法区分两族:参数 ${params.name}、环境变量 ${env.NAME}、上下文 ${context.paths.artifacts_dir}(均带命名空间);而 env: 里定义的变量在 shell 中可直接 $APP_ENV 展开(实测 5.1 输出)。UI 触发时可编辑参数(run_config.disable_param_edit: false 控制)。

5.5 handler_on:生命周期钩子

DAG 级钩子,事件含 init/success/failure/abort/exit/wait。实测失败钩子($DAGU_HOME/dags/c1-fail-demo.yaml):

description: "C1 failure handler test"
handler_on:
  failure:
    run: 'echo "ALERT: c1-fail-demo failed"'
    env:
      - ALERT_LEVEL: critical
steps:
  - id: boom
    run: sh -c "echo boom-to-stderr >&2; exit 3"

执行实测:

dagu start /var/lib/dagu/dags/c1-fail-demo.yaml

实测回显:

Failed - 2026-10-19T05:07:46Z

dag: c1-fail-demo (0s)
├─log: /var/lib/dagu/logs/c1-fail-demo/dag-run_20261019_050746Z_034iRoTL75JMlepuMroaYa/dag-run_20261019.050746.744.034iRoTL.log
│
├─boom (0s) [failed]
│ ├─sh -c "echo boom-to-stderr >&2; exit 3"
│ │
│ ├─stderr: /var/lib/dagu/logs/c1-fail-demo/dag-run_20261019_050746Z_034iRoTL75JMlepuMroaYa/run_20261019_050746Z_abd7b1/boom.20261019.050746.752.034iRoTL.err
│ │   boom-to-stderr
│ │
│ └─error: exit status 3
│
└─onFailure (0s) [succeeded]
  ├─echo "ALERT: c1-fail-demo failed"
  │
  └─stdout: /var/lib/dagu/logs/c1-fail-demo/dag-run_20261019_050746Z_034iRoTL75JMlepuMroaYa/run_20261019_050746Z_abd7b1/onFailure.20261019.050746.756.034iRoTL.out
      ALERT: c1-fail-demo failed

Result: Failed

行为解读:boom 以 exit 3 失败后,onFailure 钩子作为独立步骤执行并成功;钩子是完整 step 定义,可带 env、timeout 等。钩子执行顺序固定为「失败步骤 → onFailure」,退出码反映主流程失败。注意 run 值里含冒号/引号时整个值加引号,否则 YAML 解析报错(实测报错见第八章 Q1)。

5.6 smtp / error_mail / mail_on:邮件通知

邮件三件套建议配在 base.yaml(全局生效,所有 DAG 继承),实测追加到 /var/lib/dagu/base.yaml 尾部:

smtp:
  host: 127.0.0.1
  port: "1025"

error_mail:
  from: dagu@example.com
  to: ops@example.com
  prefix: "[DAGU]"
  attach_logs: false

mail_on:
  failure: true

逐项说明:smtp.host/port 服务器与端口(生产用 587 STARTTLS 或 465,另支持 oauth 段接 Microsoft 365/Google);error_mail 失败邮件的发件人/收件人/主题前缀/是否附日志(to 也可为数组多收件人);mail_on 开关三类事件邮件(failure/success/wait)。配套还有 info_mail(成功通知)、wait_mail(等待人工审批通知)。

执行失败的 DAG 后,本地 SMTP 服务器实测收到邮件(回显摘自 SMTP 调试日志):

---------- MESSAGE FOLLOWS ----------
mail options: ['BODY=8BITMIME']
b'To: ops@example.com'
b'From: dagu@example.com'
b'Subject: [DAGU] c1-fail-demo (failed)'
b'Date: Mon, 19 Oct 2026 05:09:15 +0000'
b'MIME-Version: 1.0'
b'Content-Type: text/html; charset=UTF-8'
b'Content-Transfer-Encoding: base64'

主题规则为 {prefix} {DAG名} ({状态}),正文为 HTML 模板(base64 编码传输)。

5.7 log_dir 与日志目录

DAG 级 log_dir 可把某工作流日志指到自定义路径;不设时默认 $DAGU_HOME/logs/<DAG名>/。实测目录结构见 5.2。日志保留由 base.yaml 全局控制:hist_retention_days: 30(按天)或 hist_retention_runs: 100(按条数,二选一),过期历史自动清理(也可手动 dagu rm --history)。

六、全局配置(base.yaml 与 dagu.env)

6.1 base.yaml 已启用的默认值(实测文件摘录)

首次启动生成的 base.yaml 即官方推荐起点,已启用项与默认值:

字段默认值含义
typegraph依赖图调度(chain 为顺序链)
overlap_policyskip运行中再触发则丢弃(all 排队 / latest 留最新)
log_outputseparatestdout/stderr 分离为 .out/.err(merged 合并单文件)
hist_retention_days30执行历史保留天数(自动清理)
max_clean_up_time_sec5停止 DAG 时等待步骤清理的最长秒数
max_active_steps10单次 DAG 运行内并行步骤上限(0 不限,仅 graph 生效)
max_output_size1048576每步捕获的 stdout/stderr 字节上限(超限截断)
catchup_window"6h"停机补跑窗口(空串禁用补跑)

关键解读:max_active_steps 与 overlap_policy 是防雪崩的两道闸——前者限制单个 DAG 内并发,后者防止上一轮未结束又叠新轮;max_output_size 防止超大 stdout 撑爆内存,需要完整大输出时应落文件而非依赖捕获。

6.2 base.yaml 注释即文档:可选块速查

base.yaml 注释段(官方内置,实测原文摘引)覆盖的可选配置块:shell(如 "bash -e")、working_dir、dotenv(执行前加载 .env 文件)、timeout_sec/delay_sec/restart_wait_sec、log_dir、queue(跨 DAG 并发组)、defaults(步骤默认值:retry_policy/continue_on/repeat_policy/timeout_sec/signal_on_stop/mail_on_error)、actions(自定义可复用动作)、handler_on、smtp/error_mail/info_mail/wait_mail/mail_on、ssh(远程执行默认:user/host/port/key/strict_host_key/bastion 跳板)、s3(含 MinIO endpoint)、redis(standalone/sentinel/cluster)、llm(openai/anthropic/gemini/openrouter/local)、otel(OpenTelemetry 导出)、registry_auths(镜像仓库凭据)、secrets(env/file/vault 三种密钥来源)、run_config(UI 运行交互控制)。每块的完整字段以本机 cat /var/lib/dagu/base.yaml 为准(注释即官方文档的可执行形态)。

6.3 dagu.env 服务端变量(实测)

变量实测值说明
DAGU_HOME/var/lib/dagu数据根目录(dags/logs/data 所在)
DAGU_HOST0.0.0.0Web 监听地址;默认 127.0.0.1 仅本机
DAGU_PORT8114Web 监听端口;默认 8080
PATH安装器快照DAG 步骤可调用的 CLI 搜索路径

⚠️ 注意:重跑官方安装器会重写本文件(DAGU_HOST 还原 127.0.0.1、端口还原 8080),升级后务必复核(实测踩坑记录见《Ubuntu 22.04 安装 Dagu 2.21.0 指南》第七章)。

七、生产配置模板

适用于 4~16GB 内存的单机生产服务器(NFS 无需、外部依赖仅邮件服务器可选),在 base.yaml 追加/覆盖:

# 全局执行与清理基线
type: graph
overlap_policy: skip
log_output: separate
hist_retention_days: 30
max_active_steps: 10
max_output_size: 1048576
max_clean_up_time_sec: 5
catchup_window: "6h"

# 步骤默认重试(幂等任务受益;非幂等任务在 DAG 内单独覆盖为 limit: 0)
defaults:
  retry_policy:
    limit: 2
    interval_sec: 5
    backoff: true
    max_interval_sec: 60

# 日志与队列(可选)
# log_dir: /var/log/dagu
# queue: default

配套 dagu.env(服务端):

DAGU_HOME=/var/lib/dagu
DAGU_HOST=0.0.0.0
DAGU_PORT=8114

场景说明:上述模板面向「数十个定时脚本、单步秒级~分钟级、失败需告警」的典型运维自动化场景;hist_retention_days 按磁盘余量调整(实测单次运行日志约几十 KB,30 天规模可控);重试默认开启指数退避是为抖动型外部依赖(HTTP/数据库)设计,纯本地脚本可改 interval_sec 固定间隔。

八、常见问题(FAQ)

Q1:YAML 报 mapping value is not allowed in this context? 值里含冒号未加引号。实测原始报错(description 值含冒号):

Error: Validation failed for /var/lib/dagu/dags/c1-retry-demo.yaml
- [1:14] mapping value is not allowed in this context
  >  1 | description: C1 field test: deps / retry / env / output passing
                      ^

定位精确到「行:列」([1:14]),把值用双引号包裹即可。run: 里的命令串同理(如 run: 'echo "ALERT: xxx"')。写完先 dagu validate <文件> 再触发。

Q2:文件里写错导致服务端报什么? 调度器实时监听文件,实测日志出现 level=ERROR msg="DAG load failed" err="[1:14] mapping value is not allowed...",修复保存后日志出现 msg="DAG added/updated",无需重启服务。巡检时 journalctl -u dagu | grep "DAG load failed" 可发现所有加载失败的工作流。

Q3:${VAR} 引用没生效/被原样输出? 区分两族语法:Dagu 内部引用是 ${params.x}、${env.X}、${context.paths.artifacts_dir}(带命名空间);shell 变量是 $APP_ENV(env: 定义的直接展开)。混用(如 shell 里写 ${APP_ENV} 带花括号)在多数 shell 下也能展开,但跨 shell 兼容性以 $VAR 写法最稳。

Q4:dry-run 成功、真实执行失败? dagu dry 不真正执行命令(模拟成功),只验证 DAG 结构。真实行为以 dagu start 为准;排障先看步骤 stderr($DAGU_HOME/logs/<DAG>/dag-run_*/run_*/<step>.*.err)与 DAG 级日志中的 Step execution failed; retrying / error: exit status N 记录。

Q5:改了 base.yaml 没生效? base.yaml 热加载(官方注释确认);若通过 dagu.env 改的是服务端变量则必须 systemctl restart dagu。另注意优先级:DAG 文件内同名键覆盖 base.yaml 全局值,确认没有在 DAG 里无意覆盖。

Q6:CLI 报找不到刚建的 DAG? CLI 未带 DAGU_HOME 时操作的是 ~/.config/dagu/dags(实测日志:dir=/root/.config/dagu/dags)。统一 export DAGU_HOME=/var/lib/dagu。

九、参考链接