Router
Route execution to different steps based on a value. Routers are graph-only control-flow actions, so set the DAG type to graph.
Basic Usage
env:
- INPUT: exact_value
steps:
- id: router
action: router.route
with:
value: ${env.INPUT}
routes:
"exact_value": [route_a]
"other": [route_b]
- id: route_a
run: echo "Route A executed"
output: RESULT_A
- id: route_b
run: echo "Route B executed"
output: RESULT_BWhen INPUT=exact_value, only route_a runs. The route_b step is skipped.
Patterns
Routes are matched against with.value.
env:
- STATUS: success_code
steps:
- id: router
action: router.route
with:
value: ${env.STATUS}
routes:
"success": [handle_success]
"re:^success.*": [handle_success_prefix]
"re:.*_code$": [handle_code]
"re:.*": [catch_all]
- id: handle_success
run: echo "Exact success"
- id: handle_success_prefix
run: echo "Success prefix"
- id: handle_code
run: echo "Code suffix"
- id: catch_all
run: echo "Default route"Rules:
- A plain key is an exact match.
- A key prefixed with
re:is a Go regular expression. - A key prefixed with
num:is a numeric comparison, using>,>=,<, or<=. - Every matching route runs, not just the first match.
- A step can be listed under more than one route. It runs once when any of those routes matches, and is skipped when none does.
- Use
re:.*as a default route.
One Step Under Several Routes
List a step under each route that should run it:
type: graph
params:
- OP: UPDATE
steps:
- id: router
action: router.route
with:
value: ${OP}
routes:
INSERT: [generate_thumbnails, index_object]
UPDATE: [generate_thumbnails]
- id: generate_thumbnails
run: echo "Generating thumbnails"
- id: index_object
run: echo "Indexing new object"With OP=UPDATE, generate_thumbnails runs once and index_object is skipped. With OP=INSERT, both run. Any other value skips both.
A step targeted by two different router steps runs only when a route of each router matches.
Numeric Routes
A num: key compares the value as a number rather than as text. Keep the routes mutually exclusive and exactly one target runs:
type: graph
env:
- SCORE: "0.95"
steps:
- id: router
action: router.route
with:
value: ${env.SCORE}
routes:
"num:>=0.9": [auto_approve]
"num:<0.9": [needs_review]
- id: auto_approve
run: echo "Approved automatically"
- id: needs_review
run: echo "Sent for review"A threshold can be a variable, written as the whole number: "num:>=${threshold}". See Numeric Comparison for the full comparison rules, which are shared with preconditions.
A numeric route fails the run on a non-numeric value
When a workflow declares any num: route and the value is not a number, the router step itself fails and no target runs. That includes a target whose pattern matches the text and a re:.* catch-all, so a catch-all cannot be used as a safety net for non-numeric input.
Because every matching route runs, a catch-all added beside numeric routes runs as well.
To send both ends of a range to one step, list it under two numeric routes, such as "num:<0.1": [needs_review] and "num:>0.9": [needs_review]. A middle band such as 0.1 < x < 0.9 has no route form, since routes listing the same step match when either one does; put those bounds on the target step as two preconditions instead.
Route Dependencies
Router target steps implicitly depend on the router step, so you do not need to repeat depends: router.
steps:
- id: setup
run: |
printf 'status=%s\n' "prod" >> "$DAGU_OUTPUT_FILE"
outputs:
- name: status
- id: route
action: router.route
with:
value: ${steps.setup.outputs.status}
routes:
prod: [deploy_prod]
stg: [deploy_stg]
depends: setup
- id: deploy_prod
run: echo "Deploying production"
- id: deploy_stg
run: echo "Deploying staging"
