Policy Orchestration
sequence and fallback define branching, sub-chain calls, and primary/fallback execution.
sequence
Purpose
Orchestrates matchers and executors into a pipeline. This is the most common entry executor.
Example Configuration
- tag: seq_main
type: sequence
args:
# Try cache first
- exec: "$cache_main"
# Stop immediately on cache hit
- matches: "has_resp"
exec: "accept"
# Arrays of matches are AND-ed together
# Examples prefer quick-setup matcher expressions directly
- matches:
- "client_ip $lan_ip_set"
- "qname $local_domains"
exec: "$hosts_main"
# Rules may also execute unconditionally
- exec: "$metrics_main"
# Only forward when no response exists yet
- matches: "!has_resp"
exec: "$forward_main"
# Normalize TTL after a response is available
- matches: "has_resp"
exec: "$ttl_main"
Configuration Details
args
- Type:
array; Required: yes; Default: none - Purpose: Defines the rule chain.
- Runtime impact:
- Rules execute in order.
- Initialization fails when the array is empty.
args[].matches
- Type:
stringorarray - Required: no
- Purpose: Match condition for the current rule.
- Runtime impact:
- Multiple conditions are combined with logical AND.
- Omitted means the rule has no precondition.
args[].exec
- Type:
string; Required: no; Default: none - Purpose: Action to run when the rule matches.
- Supports:
- plugin references
- quick setup expressions
- built-in control flow
Behavior
- Rules run sequentially.
- A rule with multiple
matchesrequires all of them to be true. - Other
sequenceinstances can be called withjumporgoto.
Built-In Control Flow
Besides plugin calls, sequence.args[].exec can also use built-in control flow:
accept
- Ends the current
sequenceimmediately. - This is an explicit early stop, so outer callers do not continue with later rules.
- Does not build a response by itself; it is usually used after an earlier stage has already produced one.
return
- Ends the current
sequenceimmediately and gives control back to the caller. - Does not build a response.
- If the current
sequencewas entered byjump, the caller continues with the next rule.
reject [rcode]
- Builds a response immediately and ends the current
sequence. - The default
rcodeisREFUSED. - Decimal numeric rcodes and case-insensitive English RCODE names are accepted, for example
reject 2,reject SERVFAIL,reject servfail, orreject NXDOMAIN; common mappings and meanings are listed in the DNS Code Reference. - Only base DNS RCODEs
0..15are supported; extended RCODEs require an EDNS OPT and are not generated by this built-in action. reject 0returns a plainNOERRORresponse and does not add an SOA automatically.- Stops later rules from running.
mark ...
- Inserts one or more integer marks, then continues to the next rule in the current
sequence. - Supports
mark 1,mark 1 2 3, andmark 1,2,3.
jump seq_tag
- Calls another
sequence; conceptually this is a subroutine call. - The parameter must be the target
sequencetag without$. - If the target
sequencereaches its tail or executesreturn, the currentsequenceresumes with the next rule. - If the target
sequenceexecutesaccept,reject, or anotherStop, the currentsequencestops too.
goto seq_tag
- Transfers control one-way to another
sequence. - The parameter must be the target
sequencetag without$. - Once
gotoruns, the currentsequencenever resumes at later rules. - If the target
sequenceexecutesreturn, thatreturnis propagated outward.
Typical Uses
- One readable top-level entry.
- Split cache, local answers, forwarding, and integrations into understandable policy layers.
- Build complex branches with marks and matchers.
Notes
- Referenced plugins must already exist.
- A
sequenceneeds at least one rule.
fallback
Purpose
Runs a primary executor first and falls back to a secondary executor when the primary is too slow or fails.
Example Configuration
- tag: fallback_main
type: fallback
args:
# Preferred path
primary: "forward_fast"
# Backup path
secondary: "forward_stable"
# Let the backup take over after 200 ms
threshold: 200
# Keep the backup running in parallel for lower tail latency
always_standby: true
Configuration Details
primary
- Type:
string; Required: yes - Purpose: Primary executor tag.
secondary
- Type:
string; Required: yes - Purpose: Secondary executor tag.
threshold
- Type:
integer; Required: no - Unit: milliseconds
- Purpose: Delay before the secondary is allowed to take over.
always_standby
- Type:
boolean; Required: no; Default:false - Purpose: Keep the secondary in standby for all requests rather than only after the threshold condition.
short_circuit
- Type:
boolean; Required: no; Default:false - Purpose: Stop the executor chain after fallback selects the winning response.
Behavior
- Provides controlled degradation instead of unconditional double-querying.
- Useful when one path is usually faster but another path is more complete or stable.
- With
short_circuitenabled, the winning branch writes its response and then immediately stops the remaining executor chain.
Metrics
Exported through the global GET /api/metrics endpoint:
fallback_primary_totalfallback_primary_error_totalfallback_secondary_total
Typical Uses
- Low-latency primary plus stable backup
- Tail-latency protection
Notes
- A too-aggressive threshold can turn the secondary into a routine dependency.