specs/080-restart-policy.md
Rama main · réplica de lectura del repositorio original.
# Spec 080: DAG Restart Policy
## Status
Implemented.
This spec defines conformance behavior for the DAG-level `restart_policy`
field: its values, how it combines with other DAG fields, and the validation
errors it produces.
## Scope
This spec covers:
- the `restart_policy` DAG field and its accepted values
- how `restart_policy` combines with `restart_wait_sec`, `schedule`,
`retry_policy`, history retention, and the base configuration
- the validation errors of a DAG that sets `restart_policy`
- the `restart` command for a DAG that sets `restart_policy`
- runs started by hand next to an active run of a DAG that sets `restart_policy`
This spec does not define:
- when the scheduler starts the runs of a DAG that sets `restart_policy`,
how they are dispatched, or timing guarantees; scheduler dispatch is
outside this conformance suite
- the `restart_policy` field of the `container` block, which configures the
Docker restart policy of a container
- `schedule.restart` and `restart_schedule`
- step-level retry or repeat behavior
- the web UI
## Goal
A workflow author can declare that a DAG is a long-running service, kept
running by Dagu instead of a cron schedule, a supervisor DAG, or an external
watchdog.
## Related Specs
- Built-in run context: [Spec 017](017-built-in-run-context.md), which defines
the `restart` trigger type
- Schedule descriptors: [Spec 063](063-schedule.md)
- Repeat policy: [Spec 075](075-repeat-policy.md), which repeats a step inside
one run
## Terms
A service DAG is a DAG whose `restart_policy` is `always` or `unless-stopped`.
## Behavior
### Field
`restart_policy` is a DAG-level field. It accepts:
| Value | Meaning |
| --- | --- |
| `no` | The DAG is not kept running. This is the default. |
| `always` | The DAG is kept running: a new run follows each run, `restart_wait_sec` after it ends, whatever its status. |
| `unless-stopped` | Same as `always`, except that no run follows a run that an operator stopped. |
Rules:
- Values are case-insensitive and surrounding whitespace is ignored.
- An empty value, or an absent field, means `no`.
- A base configuration cannot set `restart_policy` to `always` or
`unless-stopped`: it applies to every DAG, so it would turn them all into
services.
### Restrictions
A service DAG:
- must have a `restart_wait_sec` of at least 1, set in its file or inherited
from the base configuration
- must not define a schedule in its file: `schedule`, in any of its forms,
including `start`, `stop` and `restart`. An empty `schedule` defines none.
- must not define a DAG-level `retry_policy` in its file
A schedule or a DAG-level `retry_policy` that a service DAG would inherit from
the base configuration is ignored.
A service DAG may set `queue`, `timeout_sec`, `max_clean_up_time_sec`, history
retention, `handler_on`, `preconditions`, and any other field.
### History Retention
A service DAG adds a run to its history each time it is restarted, so days of
runs do not bound its history:
- a `hist_retention_days` in its file applies
- a `hist_retention_days` in the base configuration does not apply
- a `hist_retention_runs` in its file or in the base configuration applies
A service DAG left without a retention keeps its latest 100 runs, where other
DAGs keep 30 days of runs.
### Restart Command
The `restart` command fails for a service DAG, without stopping or starting a
run: the runs of a service DAG are started for it. The command reads the
current definition of the DAG, so it also fails for a DAG that has no run yet,
or whose `restart_policy` was set after its latest run started.
### Runs Started by Hand
A service DAG has one run at a time. While its latest run is running, queued or
waiting, or has not started for up to 5 minutes, the `start`, `enqueue` and
`retry` commands, their API requests and MCP actions, and webhooks fail without
starting a run. With no active run they work, which is how a stopped service
comes back.
The current definition of the DAG decides whether it is a service, also for a run
started from a run snapshot or from a spec in a request. The run that the
scheduler dispatches from the queue is refused only when another run of the DAG
has a live process on the same host; it then ends as failed. A run started under
another name with `--name` is a run of another DAG.
## Errors
Rules:
- A `restart_policy` that is not `no`, `always` or `unless-stopped` fails
validation on the field `restart_policy`.
- A service DAG with a missing or non-positive `restart_wait_sec` fails
validation on the field `restart_wait_sec`.
- A service DAG that defines a schedule fails validation on the field
`restart_policy`.
- A service DAG that defines a DAG-level `retry_policy` fails validation on
the field `restart_policy`.
- A base configuration that sets `restart_policy` to `always` or
`unless-stopped` fails validation on the field `restart_policy`, and so does
every DAG that uses it.
- The `restart` command for a service DAG exits with a non-zero status and an
error that names `restart_policy`.
- A `start`, `enqueue` or `retry` command next to an active run of a service DAG
exits with a non-zero status and an error that names `restart_policy`. The API
responds with the status 409.
## Examples
A worker that is started again 5 seconds after each run ends:
```yaml
restart_policy: always
restart_wait_sec: 5
hist_retention_runs: 100
steps:
- run: python3 worker.py
```
A server that stays down once an operator stops it:
```yaml
restart_policy: unless-stopped
restart_wait_sec: 10
hist_retention_runs: 100
steps:
- run: ./serve.sh
```
A health probe that checks every 10 seconds within one run:
```yaml
restart_policy: always
restart_wait_sec: 15
hist_retention_runs: 100
steps:
- run: ./check.sh
repeat_policy:
repeat: while
exit_code: [0]
interval_sec: 10
handler_on:
failure:
run: ./alert.sh
```
Rejected:
```yaml
restart_policy: always
restart_wait_sec: 5
schedule: "* * * * *"
steps:
- run: echo tick
```
```yaml
restart_policy: always
steps:
- run: echo tick
```
```yaml
restart_policy: sometimes
restart_wait_sec: 5
steps:
- run: echo tick
```
## Conformance
`conformance/spec080_restart_policy/` checks the validation rules with static
fixtures, the `restart` command for a service DAG, and the commands that start a
run next to its active run.