docs / reference
Tasks
Every field a task accepts — action, timeout, only_once, on_error, output, switch — and the six action types.
A task is one unit of work in a process definition. Every task has an id and a switch;
everything else is optional. A task with no action is a pure routing task.
Fields
| Field | Type | Meaning |
|---|---|---|
id | string | Unique task identifier. end and next are reserved and cannot be used. |
action | object | The action to perform. Omit for switch-only (routing) tasks. |
timeout | duration | object | Maximum execution time, honoured by fetch and external tasks. |
only_once | boolean | At-most-once execution. Defaults to false. |
on_error | list | Ordered error-routing rules evaluated when the action fails. First match wins. |
output | value | Templated value that remaps this task’s output. |
switch | string | list | Required. Where control goes next. |
timeout
Either a duration shorthand — "30s", "2h30m", a bare number of milliseconds, or a $:
expression evaluating to milliseconds, all resolved in UTC — or an object naming exactly one
of for / until, plus an optional tz.
until is an absolute deadline and is accepted only on an external task.
Omit it for no timeout of its own: a fetch falls back to the engine default, an external
waits indefinitely.
only_once
When true, the engine guarantees at-most-once execution:
- Retries are allowed only for
pre.*codes (the remote was never reached) or foron_errorrules carryingnot_reached: true. - A rule that is not restricted to
pre.*needsnot_reached: trueand must name exact codes — no wildcards. http.timeout,external.timeoutandonly_once.interruptedcan never be retried at all: the request left and nothing came back, so nothing can be asserted about it.
An attempt cut short by a crash raises only_once.interrupted, which on_error can catch —
typically to ask the system of record what happened and then carry on.
output
Evaluated against the context plus self.result (the action’s raw result) and
self.previous (this task’s prior output — non-empty when a loop re-enters the task).
When output is set, its value is stored as outputs.<taskID> and seen by the switch as
self.output; the raw result is not exported. It is computed only when the action
succeeds.
switch
Scalar shorthand — "next", "end", "$task-id" — or an ordered list of cases. next
advances to the next task in the list and is invalid on the last one; end terminates the
instance.
The last case must be a catch-all, with case omitted.
| Key | Meaning |
|---|---|
case | Expression selecting this arm. Omit on the final catch-all. |
goto | Task to route to: $task-id or end. |
raise | Terminate as raised with a code / message. |
panic | Terminate as failed with a code / message. |
switch:
- case: "self.output.attempt >= input.max_attempts"
raise:
code: poll_timeout
message: "gave up after max_attempts polls"
- goto: $check
on_error
| Key | Meaning |
|---|---|
code | Patterns matched against the error code. Empty list = catch-all. |
retry | Retry policy applied before the rule routes. Omit for no retries. |
goto | Task to route to when retries are exhausted: $task-id or end. Omit to fail the instance. |
raise | Terminate as raised with this code and message instead of routing. Mutually exclusive with goto and panic. |
panic | Terminate as failed with this code and message instead of routing. Mutually exclusive with goto and raise. |
not_reached | Assert that this code means the remote call was never reached. |
Code patterns
% is the only wildcard and matches any run of characters. Every other character —
including _ and . — is literal, so order_% matches order_placed but not
order.placed.
Catchable engine codes, reported by an action task’s call:
| Code | Raised when |
|---|---|
http.NNN | The response status is outside accepted_status (e.g. http.500, http.202). |
http.timeout | The request left and no response came back in time. |
pre.error, pre.timeout | The call never reached the remote. |
output.parse | The response body is not valid JSON. |
output.too_large | The response body exceeds the fetch response cap. |
output.invalid | The result does not validate against result_schema. |
external.timeout | An external task’s deadline passed with no submitted result. |
Internal engine.* failures — engine.spawn, engine.collect, engine.expression — are
terminal and are not routed through on_error.
On a child, child_map or child_list task the codes match the codes the child processes
can raise, and each pattern is checked at registration against the child’s raise set. A
child that failed rather than raised is never catchable; convert the failure into a raise
inside the child.
retry
A bare attempt count, or an object naming any of attempts, delay, factor, max_delay.
on_error:
- code: [http.5%]
retry: { attempts: 5, delay: "2s", factor: 2, max_delay: "1m" }
goto: $compensate
Not supported on child tasks — retry inside the child, then raise.
Action types
type | Required | Result |
|---|---|---|
fetch | url | The response body. |
child | name | That child’s output, unwrapped. |
child_map | children | An object keyed by child name. |
child_list | name, over | An array of the children’s outputs, in over’s order. |
delay | exactly one of for / until | — |
external | — | The submitted result. |
fetch
An HTTP call, shaped like fetch(url, {method, headers, body}). Every field is an
expression, so the whole request can come from the context.
| Field | Meaning |
|---|---|
url | Request URL. |
method | HTTP method. Defaults to POST. |
headers | A value evaluating to a string map. |
body | Templated request body, sent raw — an object as JSON. |
accepted_status | Array of status patterns treated as non-errors: "2xx"…"5xx", or a 3-digit code. Defaults to any 2xx. |
result_schema | Validates the response before the instance resumes. Without it the result is available only as self in this task’s switch. |
X-Genroc-Instance-Id and X-Genroc-Task-Id are stamped on every request authoritatively,
so a caller-supplied header cannot spoof them.
child, child_map, child_list
| Field | On | Meaning |
|---|---|---|
name | child, child_list | Child process to invoke. |
version | all | Version to run; 0 means the latest published version. |
input | child, child_map entries | Templated value building the child’s input payload. |
over | child_list | A $: expression evaluating to an array. One child per element, the element being its input. An empty array spawns nothing and yields []. |
children | child_map | Keyed map of children run concurrently. Keys become the access names in outputs.<taskID>. |
result_schema | all | Validates and exposes the child’s output — per element for child_list. |
Declaring a shape where the child left a value untyped ({}, the top type) narrows it: the
collected output is conformed against the schema, and undeclared keys are dropped.
delay
Parks the instance until a duration elapses (for) or an instant arrives (until), without
holding a worker, then routes via switch. Exactly one of the two.
| Field | Accepts |
|---|---|
for | "2h30m", "1d 12h" (units ms, s, m, h, d, w, mo, y), a bare number of milliseconds, or a $: expression evaluating to milliseconds. A quoted number without a unit is rejected as ambiguous. |
until | "2026-09-01T08:00:00+02:00" (RFC 3339), "2026-09-01 08:00" (in tz), "+2d 08:00", "*-*-01 08:00", "mon 09:00", "*:*:00" (every whole minute; any clock field may be * or a base/step — "*:*:0/5" is every five seconds), a bare number of unix milliseconds, or a $: expression evaluating to unix milliseconds. An instant already past resolves immediately. |
tz | IANA name ("Europe/Prague") or fixed offset ("+02:00"). Defaults to UTC. Abbreviations such as CET are rejected — they are ambiguous across DST. |
external
Parks the instance until an outside caller submits a result through the external-tasks API. No worker is held while waiting.
| Field | Meaning |
|---|---|
input | Templated value, snapshotted and exposed to the resolver through the queue — the only context the resolver sees. |
result_schema | Validates the submitted result before the instance resumes. Without it any JSON result is accepted. |
An optional task timeout raises the catchable external.timeout; absent, it waits forever.
This is the one place an absolute until deadline is accepted.