Pular para o conteúdo principal

Decisões e Gateways

Um EXCLUSIVE_GATEWAY roteia o fluxo para exatamente um ramo de saída, com base em uma decisão. A decisão em si nunca é uma expressão embutida em string — é sempre o retorno de um método Java, ou o valor de uma variável de processo já calculada.

Pense na triagem de um pronto-socorro

A mesma entrada leva a caminhos completamente diferentes dependendo de uma avaliação objetiva: casos graves seguem para um caminho, casos leves para outro. A avaliação acontece uma vez, no momento em que o paciente chega, com base em critérios definidos. A analogia para de funcionar se você esperar que a triagem reavalie o paciente continuamente — um gateway do Kikwiflow decide uma única vez, no instante em que o fluxo passa por ali, e não reconsidera a decisão depois.

"E se o score for baixo — quero mandar para uma mesa de análise?"​

Imagine um processo de abertura de conta que manda toda solicitação direto para o mesmo analista. Um gateway resolve isso: logo depois do cálculo do score, uma decisão de negócio separa quem segue para a aprovação comum de quem precisa passar por uma mesa de análise mais rígida antes.

O contrato AnswerProvider​

@FunctionalInterface
public interface AnswerProvider {
/**
* Avalia o contexto atual e retorna uma String representando a hipótese de resposta.
* Retornar nulo é permitido, mas deve ser tratado explicitamente no modelo do processo.
*/
String resolve(EvaluationContext context);
}

As duas estratégias de providerType​

Um EXCLUSIVE_GATEWAY resolve sua decisão de uma entre duas formas, declaradas via providerType:

providerTypeOrigem da decisãoCampo relevante
BEANBean Spring implementando AnswerProviderproviderBean
VARIABLEUma variável de processo já calculada por um nó anteriorproviderVariable

providerType: BEAN — a faixa de risco​

A decisão depende de uma regra de negócio (a faixa em que o score cai), então é código Java:

package com.empresa.processo.decision;

import io.kikwiflow.execution.api.context.EvaluationContext;
import io.kikwiflow.execution.api.provider.AnswerProvider;
import org.springframework.stereotype.Component;

@Component("faixaRiscoAnswerProvider")
public class FaixaRiscoAnswerProvider implements AnswerProvider {

@Override
public String resolve(EvaluationContext context) {
int score = (int) context.getVariableValue("score").orElseThrow();
return score < 700 ? "ALTO" : "NORMAL";
}
}
{
"id": "GATEWAY_FAIXA_RISCO",
"name": "Qual a faixa de risco?",
"type": "EXCLUSIVE_GATEWAY",
"providerType": "BEAN",
"providerBean": "faixaRiscoAnswerProvider",
"outgoing": [
{ "id": "flow-comum", "targetNodeId": "APROVAR_ABERTURA", "isDefault": true },
{ "id": "flow-mesa", "targetNodeId": "ANALISE_MESA", "expectedAnswer": "ALTO" }
]
}

Score de risco alto (< 700) segue para Análise de Mesa; qualquer outra resposta (NORMAL, ou um valor novo que o provider passe a devolver no futuro) cai na aresta isDefault e vai direto para Aprovar Abertura.

providerType: VARIABLE — o resultado da mesa​

Quando a resposta já foi calculada por um nó anterior — por exemplo, um analista sênior que digitou a decisão ao completar a tarefa externa Análise de Mesa — o gateway só precisa lê-la como variável:

{
"id": "GATEWAY_RESULTADO_MESA",
"type": "EXCLUSIVE_GATEWAY",
"providerType": "VARIABLE",
"providerVariable": "resultadoMesa",
"outgoing": [
{ "id": "flow-mesa-aprova", "targetNodeId": "APROVAR_ABERTURA", "expectedAnswer": "APROVADA" },
{ "id": "flow-mesa-recusa", "targetNodeId": "END_RECUSADA", "isDefault": true }
]
}

Como a aresta de saída é escolhida​

Dada a resposta resolvida (por BEAN ou VARIABLE), o motor escolhe a primeira aresta cujo expectedAnswer seja igual (comparação exata de string); se a resposta for null, escolhe a aresta com handlesNull: true; se nenhuma casar, escolhe a aresta isDefault: true, se existir.

Sempre declare uma aresta isDefault

Sem uma aresta isDefault, uma resposta inesperada (que não bate com nenhum expectedAnswer nem é null) não tem para onde ir. Declare isDefault: true sempre que o AnswerProvider puder evoluir com novos valores de resposta com o tempo, e handlesNull: true sempre que ele puder legitimamente retornar null — uma resposta null nunca cai na aresta isDefault: sem uma aresta handlesNull, ela vira IllegalStateException em execução. No exemplo da faixa de risco, o caminho comum (NORMAL) é o default, não um expectedAnswer explícito.

Declarar no Craft​

No Craft, o gateway é um Decision. Ao conectar a saída de um Decision, a conexão nasce exigindo configuração de rota — marque uma como rota padrão (isDefault) e dê à outra o valor esperado (ALTO). O gateway providerType: VARIABLE não precisa de bean nenhum: ele lê uma variável que a tarefa externa anterior já gravou.

Quando usar / quando não usar​

Use um EXCLUSIVE_GATEWAY quando o fluxo precisa escolher um entre vários caminhos com base em uma condição avaliada uma vez.

Não use quando:

  • Você quer executar vários passos ao mesmo tempo (não escolher um) — isso é Processamento Paralelo.
  • A decisão depende de esperar alguém — modele a espera como EXTERNAL_TASK e leia o resultado num gateway providerType: VARIABLE depois, como no exemplo do resultado da mesa acima.

Próximo passo​

Gateways decidem para onde o fluxo vai. Para decidir quando algo acontece — prazos, expiração, lembretes — veja Timers e Prazos.