Controle de fluxo
branch/switch/foreach/parallel/try/group compõem lógica condicional e iterativa sem
sair do YAML.
when: o caminho barato
Todo step aceita três campos universais:
| Campo | Efeito |
|---|---|
type |
Obrigatório. A chave que resolve a implementação |
id |
Opcional. Publica o resultado em steps.<id>.result |
when |
Opcional. Expressão booleana; o step só executa se verdadeira |
when é mais barato que branch para o caso comum de pular um único step:
- { type: db.find, id: found, entity: widget, where: { id: "input.route.id" } }
- { type: fail, when: "steps.found.result = null", status: 404, code: WIDGET_NOT_FOUND }
- type: return
Use branch/switch quando o que muda é qual grupo de steps roda, não se um único step roda.
Os steps de controle de fluxo
| Step | Função |
|---|---|
branch |
when (campo do próprio step, seleciona entre os dois ramos) / then / else |
switch |
cases: [{ when, then }], mais default |
foreach |
in (expressão), steps, parallelism opcional (default 1), collect: { to, select } |
parallel |
branches: [[...], [...]] — sub-pipelines independentes, executados concorrentemente |
try |
try / catch opcional / finally opcional — a falha fica disponível em error dentro de catch |
group |
Agrupa steps só para legibilidade/organização, sem when próprio nem outro efeito |
branch é o único step com when como campo do próprio bloco — ele escolhe entre then e else.
Todo outro step usa o when universal descrito acima.
- type: switch
cases:
- { when: "input.body.type = 'premium'", then: [ { type: map, to: vars.discount, expr: "0.2" } ] }
- { when: "input.body.type = 'standard'", then: [ { type: map, to: vars.discount, expr: "0.1" } ] }
default: [ { type: map, to: vars.discount, expr: "0" } ]
- type: foreach
in: "input.body.items"
steps:
- { type: map, id: line, to: vars.line, expr: "{ 'sku': $item.sku, 'total': $item.price * $item.quantity }" }
collect:
to: vars.lines
select: vars.line
- type: try
try:
- { type: http.call, integration: pricing, method: POST, path: /quote }
catch:
- { type: log, message: "'falha ao consultar preço: ' & error.message" }
- { type: map, to: vars.price, expr: "0" }
Escopo de id e de vars
Cada bloco composto (then/else/cases[].then/default/foreach.steps/parallel.branches/
try/catch/finally) tem seu próprio escopo de ids — uma referência steps.<id> de fora
desse bloco falha o build, não silenciosamente em runtime.
vars, ao contrário, não é escopado por bloco: uma escrita feita dentro de um
foreach/try/etc. permanece visível depois dele.
Um detalhe que morde: transação e concorrência
Não misture db.* concorrente com transaction: required. Um parallel com mais de um ramo
fazendo db.*, ou um foreach com parallelism > 1 chamando db.*, dentro de uma rota
transacional, colide — a sessão transacional é uma única conexão, não é seguro usá-la
concorrentemente.
Duas formas seguras de evitar isso:
- Pareie no máximo um ramo de
db.*com computação pura dentro deparallel(o outro ramo não toca o banco). - Rode o
foreachsequencial (parallelism: 1, que já é o valor padrão) sempre que ele fazdb.*dentro de uma rota transacional.
Para onde ir daqui
- Autenticação e autorização
- Integrações outbound —
try/catché frequentemente combinado comhttp.call/grpc.callpara tratar falhas de um sistema externo.