pub type Action = Task;Expand description
Type alias for Task — an Action is an individual processing step within a rule.
Aliased Type§
pub struct Action {
pub id: String,
pub name: String,
pub description: Option<String>,
pub condition: Value,
pub function: FunctionConfig,
pub continue_on_error: bool,
pub terminal: bool,
pub halt_on: HaltOn,
/* private fields */
}Fields§
§id: StringUnique identifier for the task within the workflow.
name: StringHuman-readable name for the task.
description: Option<String>Optional description explaining what the task does.
condition: ValueJSONLogic condition that determines if the task should execute.
Conditions can access any context field (data, metadata, temp_data).
Defaults to true (always execute).
function: FunctionConfigThe function configuration specifying what operation to perform. Can be a built-in function (map, validation) or a custom function.
continue_on_error: boolWhether to continue workflow execution if this task fails.
When true, errors are recorded but don’t stop the workflow.
Defaults to false.
“Fails” means a 5xx outcome or a returned Err — not every
unsuccessful task. A 4xx is logged as a warning and the workflow
carries on regardless of this flag, so continue_on_error: false after a
validation task does not stop the tasks that follow it: a failing rule
returns 400. To gate on an outcome, use Task::halt_on; to reject the
whole message, return an Err from a handler.
terminal: boolWhether running this task ends the workflow. Defaults to false.
terminal is a statement about position — “nothing after this runs” —
not about outcome:
- a false
conditionmeans the task never ran, so nothing halts; TaskOutcome::Skipdoes not halt, for the same reason;- a task that failed under
continue_on_error: truestill halts, and its error is still recorded onmessage.errors().
Halting stops this workflow only; later workflows registered on the same
engine still process the message. Inside a workflow carrying a
LoopConfig it breaks the whole
loop, not one sweep — the same scope as
TaskOutcome::Halt.
The audit-trail entry keeps the task’s own status (200, 404, …)
rather than HALT_STATUS_CODE: the task did its job, and a map that
wrote a 404 response body should not report “a filter halted here”.
For the outcome axis — “halt only if this task failed” — see
Task::halt_on.
halt_on: HaltOnHalt the workflow based on this task’s outcome. Defaults to
HaltOn::Never.
The complement of Task::terminal: terminal is about position and
halts whatever happened, halt_on is about what happened and halts only
then. The two combine as terminal || (halt_on matched) — terminal is
strictly stronger, so setting both is redundant rather than contradictory.
This is what lets an assertion reject. A validation task returns 400
when a rule fails, which is not covered by
continue_on_error, so without halt_on the
tasks after it still run:
{ "id": "check_state", "halt_on": "failure",
"function": { "name": "validation", "input": { "rules": [ … ] } } }Failure means a recorded status of 400 or above — the same
threshold the executor already splits on to warn (4xx) and to record
TASK_STATUS_ERROR (5xx) — or a handler returning Err, recorded as
500. It is deliberately not “the task appended to
message.errors()”: a handler may call
TaskContext::add_error and still
return Success, and that does not halt.
| The task … | terminal: true | halt_on: "failure" |
|---|---|---|
never ran (its condition, or its group’s, was false) | no | no |
returned TaskOutcome::Skip | no | no |
returned Success, or a 2xx–3xx status | halts | no |
returned TaskOutcome::Halt | halts already | halts already |
| returned a 4xx status | halts | halts |
returned 5xx, continue_on_error: true | halts | halts |
returned 5xx, continue_on_error: false | error propagates | error propagates |
handler returned Err, continue_on_error: true | halts | halts |
handler returned Err, continue_on_error: false | error propagates | error propagates |
called add_error but returned Success | halts | no |
The two “error propagates” rows are not an omission: the executor returns
Err before either flag is consulted, which abandons the rest of this
workflow — everything halting would have done — and additionally reaches
the caller. They differ in exactly one shape: a workflow carrying a
loop whose own
continue_on_error is true, where the error advances to the next sweep
while a halt would break the loop. Set continue_on_error: false on the
workflow if the loop must stop.
Everything terminal documents about scope applies unchanged: halting
stops this workflow only, later workflows still process the message, it
breaks a whole loop rather than one sweep, and the audit entry keeps the
task’s own status — 400, not HALT_STATUS_CODE. Halting is therefore
not a security control: to stop a message outright return an Err, or
gate the following workflow on
EngineBuilder::with_error_context_path.