genroc

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

FieldTypeMeaning
idstringUnique task identifier. end and next are reserved and cannot be used.
actionobjectThe action to perform. Omit for switch-only (routing) tasks.
timeoutduration | objectMaximum execution time, honoured by fetch and external tasks.
only_oncebooleanAt-most-once execution. Defaults to false.
on_errorlistOrdered error-routing rules evaluated when the action fails. First match wins.
outputvalueTemplated value that remaps this task’s output.
switchstring | listRequired. 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 for on_error rules carrying not_reached: true.
  • A rule that is not restricted to pre.* needs not_reached: true and must name exact codes — no wildcards.
  • http.timeout, external.timeout and only_once.interrupted can 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.

KeyMeaning
caseExpression selecting this arm. Omit on the final catch-all.
gotoTask to route to: $task-id or end.
raiseTerminate as raised with a code / message.
panicTerminate 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

KeyMeaning
codePatterns matched against the error code. Empty list = catch-all.
retryRetry policy applied before the rule routes. Omit for no retries.
gotoTask to route to when retries are exhausted: $task-id or end. Omit to fail the instance.
raiseTerminate as raised with this code and message instead of routing. Mutually exclusive with goto and panic.
panicTerminate as failed with this code and message instead of routing. Mutually exclusive with goto and raise.
not_reachedAssert 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:

CodeRaised when
http.NNNThe response status is outside accepted_status (e.g. http.500, http.202).
http.timeoutThe request left and no response came back in time.
pre.error, pre.timeoutThe call never reached the remote.
output.parseThe response body is not valid JSON.
output.too_largeThe response body exceeds the fetch response cap.
output.invalidThe result does not validate against result_schema.
external.timeoutAn 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

typeRequiredResult
fetchurlThe response body.
childnameThat child’s output, unwrapped.
child_mapchildrenAn object keyed by child name.
child_listname, overAn array of the children’s outputs, in over’s order.
delayexactly one of for / until
externalThe 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.

FieldMeaning
urlRequest URL.
methodHTTP method. Defaults to POST.
headersA value evaluating to a string map.
bodyTemplated request body, sent raw — an object as JSON.
accepted_statusArray of status patterns treated as non-errors: "2xx""5xx", or a 3-digit code. Defaults to any 2xx.
result_schemaValidates 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

FieldOnMeaning
namechild, child_listChild process to invoke.
versionallVersion to run; 0 means the latest published version.
inputchild, child_map entriesTemplated value building the child’s input payload.
overchild_listA $: expression evaluating to an array. One child per element, the element being its input. An empty array spawns nothing and yields [].
childrenchild_mapKeyed map of children run concurrently. Keys become the access names in outputs.<taskID>.
result_schemaallValidates 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.

FieldAccepts
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.
tzIANA 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.

FieldMeaning
inputTemplated value, snapshotted and exposed to the resolver through the queue — the only context the resolver sees.
result_schemaValidates 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.