Pular para o conteúdo principal
Página não listada
Esta página não está listada. Mecanismos de busca não irão indexá-la, e somente usuários que possuam o link direto poderão acessá-la

Modelo de Processo e Nós de Fluxo

Um processo Kikwiflow é representado em runtime por io.kikwiflow.model.definition.process.ProcessDefinition — um record imutável carregando key, version, checksum, defaultStartPoint e, principalmente, um mapa flowNodes: Map<String, FlowNodeDefinition> indexado pelo id de cada nó do grafo.

public record ProcessDefinition(
String id, String sla, Integer version, String key, String name, String description,
Map<String, FlowNodeDefinition> flowNodes, String defaultStartPoint,
String checksum, Map<String, String> extensionProperties) { ... }

O checksum é calculado pelo parser (kikwi-parser-jackson) a cada deploy; se o conteúdo enviado for idêntico a uma versão já implantada para a mesma key, o deploy é um no-op e a versão existente é retornada — isso é o que torna o autodeploy no boot da aplicação idempotente entre reinícios.

FlowNodeDefinition: uma interface selada

Todo nó do grafo implementa a interface selada (sealed interface) FlowNodeDefinition, o que significa que o compilador Java conhece o conjunto fechado de subtipos possíveis — útil para switch/instanceof exaustivos dentro do próprio motor e para IDEs oferecerem autocomplete preciso ao lidar com o modelo:

public sealed interface FlowNodeDefinition permits StartEventDefinition,
ExternalTaskDefinition, ExecutableTaskDefinition, EndEventDefinition,
ExclusiveGatewayDefinition, InterruptiveTimerEventDefinition, BoundaryEventDefinition,
ParallelGatewayDefinition, JoinGatewayDefinition, NonInterruptiveTimerEventDefinition,
ErrorHandlerDefinition, CallActivityDefinition, EventCatcherDefinition,
InterruptiveCatchEventDefinition, TimerTaskDefinition, EventThrowerDefinition {

String id();
String name();
String type();
String description();
Boolean commitAfter();
Boolean commitBefore();
List<SequenceFlowDefinition> outgoing();
Map<String, String> extensionProperties();
LayoutCoordinates layout();
}

Todo nó, portanto, carrega commitBefore/commitAfter — os dois campos que controlam se o motor deve parar e persistir uma fronteira transacional antes ou depois de processar aquele nó. Esse mecanismo é central o suficiente para merecer sua própria página: veja Execução Síncrona e Assíncrona.

Dispatch polimórfico no JSON

O parser (kikwi-parser-jackson, classe FlowNodeDefinitionMixin) resolve qual subtipo Java instanciar a partir do campo "type" de cada entrada em flowNodes:

type no JSONClasse JavaMarca de interface adicional
DEFAULT_START_EVENTStartEventDefinition
DEFAULT_END_EVENTEndEventDefinition
EXECUTABLE_TASKExecutableTaskDefinitionExecutable
EXTERNAL_TASKExternalTaskDefinitionWaitState
EXCLUSIVE_GATEWAYExclusiveGatewayDefinition
PARALLEL_GATEWAYParallelGatewayDefinition
JOIN_GATEWAYJoinGatewayDefinition
BOUNDARY_INTERRUPTIVE_TIMERInterruptiveTimerEventDefinitionBoundaryEventDefinition
BOUNDARY_NON_INTERRUPTIVE_TIMERNonInterruptiveTimerEventDefinitionBoundaryEventDefinition
BOUNDARY_ERROR_HANDLERErrorHandlerDefinitionBoundaryEventDefinition
EVENT_CATCHEREventCatcherDefinitionWaitState
BOUNDARY_INTERRUPTIVE_CATCH_EVENTInterruptiveCatchEventDefinitionBoundaryEventDefinition
TIMER_TASKTimerTaskDefinition
EVENT_THROWEREventThrowerDefinition
CALL_ACTIVITY_COORDINATORCallActivityDefinition

As marcas de interface (Executable, WaitState, BoundaryEventDefinition) são usadas pelo motor para decidir comportamento sem precisar de instanceof em cascata em todo lugar — por exemplo, ProcessExecutionManager verifica flowNodeDefinition instanceof WaitState para saber se deve suspender a execução (ver Execução Síncrona e Assíncrona).

:::info Subprocessos: CALL_ACTIVITY_COORDINATOR CallActivityDefinition ("type": "CALL_ACTIVITY_COORDINATOR" no JSON) inicia uma ou mais instâncias de outra ProcessDefinition e só segue adiante quando todas concluem — o subprocesso/call activity do Kikwiflow. Não implementa Executable nem WaitState (o fan-out e a espera são tratados por mecanismo próprio, não pelo TaskExecutor/WaitState genéricos). Ver o guia dedicado: CALL_ACTIVITY_COORDINATOR — Subprocessos. :::

:::info Correlação de eventos: EVENT_CATCHER, BOUNDARY_INTERRUPTIVE_CATCH_EVENT e EVENT_THROWER Três tipos formam a família de correlação por chave de negócio do Kikwiflow — em vez de um worker puxar trabalho (fetch-and-lock), um evento externo (webhook, mensagem assíncrona) empurra a chave que destrava a espera, via KikwiflowEngine.correlateMessage(...):

  • EVENT_CATCHER (EventCatcherDefinition, implementa WaitState) — nó principal de espera reativa, com modo STANDALONE (uma chave) ou GROUP (N chaves em scatter-gather). Ver EVENT_CATCHER e EVENT_THROWER no Guia do Desenvolvedor.
  • BOUNDARY_INTERRUPTIVE_CATCH_EVENT (InterruptiveCatchEventDefinition, implementa BoundaryEventDefinition) — o mesmo mecanismo de correlação, mas como evento de borda: cancela o nó pai assim que a chave chega. Ver Boundary Catch Event.
  • EVENT_THROWER (EventThrowerDefinition) — a contraparte de emissão: resolve uma chave e entrega internamente pelo mesmo caminho de correlateMessage, sem implementar Executable nem WaitState (o comportamento de lançar é embutido no motor, não delega a um TaskHandler, e não bloqueia quem lançou). Ver EVENT_CATCHER e EVENT_THROWER. :::

:::info Temporizador de fluxo principal: TIMER_TASK TimerTaskDefinition ("type": "TIMER_TASK" no JSON) pausa a execução até um dueDate calculado (STATIC/VARIABLE/BEAN, o mesmo mecanismo de InterruptiveTimerEventDefinition) e então segue pelas próprias arestas de saída — um temporizador que faz parte do fluxo principal, não um evento de borda anexado a outro nó. Materializado como ExecutableTask (não ExternalTask); não implementa WaitState. Ver TIMER_TASK no Guia do Desenvolvedor. :::

Anatomia de um nó EXECUTABLE_TASK

A tarefa executável é o nó que carrega lógica Java síncrona, executada in-process pelo TaskExecutor:

{
"id": "CALCULATE_CUSTOMER_RISK_ST",
"name": "Calcular Risco",
"type": "EXECUTABLE_TASK",
"executor": "calculateCustomerRiskTaskHandler",
"commitBefore": false,
"commitAfter": false,
"outgoing": [ { "targetNodeId": "GATEWAY-CLASSIFICACAO-RISCO" } ]
}
CampoTipoDescrição
executorStringNome do bean Spring TaskHandler a invocar. Ver Visão Geral.
retryPolicyRetryPolicyPolítica de nova tentativa específica do nó. Ver Retry e Resiliência.
boundaryEventIdsList<String>IDs de nós de borda anexados (timers, error handlers).
commitBefore / commitAfterBooleanFronteiras transacionais.

Anatomia de um nó EXTERNAL_TASK

Uma tarefa externa não referencia nenhum bean — ela representa trabalho que será concluído fora do processo Java em execução (um worker externo, uma ação humana via UI, uma integração assíncrona). O motor cria um registro ExternalTask e aguarda uma chamada explícita a KikwiflowEngine.completeExternalTask(...) (exposta via REST em PUT /external-tasks/{id}/complete pelo kikwi-management-rest) para prosseguir.

{
"id": "wait-customer-registry",
"name": "Aguardar Cadastro",
"sla": "PT2M",
"type": "EXTERNAL_TASK",
"commitBefore": false,
"commitAfter": false,
"outgoing": [ { "targetNodeId": "do-customer-registry-activation" } ],
"boundaryEvents": [ { "type": "BOUNDARY_INTERRUPTIVE_TIMER", "staticValue": "PT1M" } ]
}

Detalhes de ciclo de vida (claim/unclaim/complete) estão em Workers e Tarefas Externas.

Anatomia de um nó EVENT_CATCHER

Como EXTERNAL_TASK, também implementa WaitState — mas em vez de ser destravado por taskId via completeExternalTask, é destravado por uma chave de correlação de negócio via KikwiflowEngine.correlateMessage(correlationKey, variables, identityContext). O campo catchType decide entre aguardar uma única chave (STANDALONE) ou N chaves em scatter-gather (GROUP, com matchPolicy: ALL ou ANY):

{
"id": "WAIT_ORDER_PAID",
"type": "EVENT_CATCHER",
"catchType": "STANDALONE",
"providerType": "VARIABLE",
"providerVariable": "orderId",
"keyPrefix": "ORDER_",
"keySuffix": "_PAID",
"outgoing": [ { "targetNodeId": "prepare-shipment" } ]
}

Cobertura completa (modo GROUP, CorrelationKeysProvider, timers de borda, idempotência) em EVENT_CATCHER — Correlação de Eventos.

Arestas: SequenceFlowDefinition

Toda aresta de saída (outgoing) de um nó é um SequenceFlowDefinition:

public record SequenceFlowDefinition(
String id, String name, String description,
String expectedAnswer, String targetNodeId,
boolean isDefault, boolean handlesNull,
List<LayoutCoordinates> positionHandlers) {}

Para nós que não são gateways, o motor sempre segue a primeira entrada de outgoing — nós não-gateway suportam apenas uma saída lógica (embora positionHandlers/layout possam sugerir curvas visuais no editor gráfico). Os campos expectedAnswer, isDefault e handlesNull só têm efeito em nós EXCLUSIVE_GATEWAY; veja Navegação e Gateways de Decisão.

Gateways estruturais: PARALLEL_GATEWAY e JOIN_GATEWAY

Diferente do gateway exclusivo, esses dois nós não carregam nenhuma configuração de decisão — são puramente estruturais:

public record ParallelGatewayDefinition(..., String targetJoinId, ...) implements FlowNodeDefinition {}
public record JoinGatewayDefinition(..., String sourceSplitId, ...) implements FlowNodeDefinition {}
  • ParallelGatewayDefinition.targetJoinId aponta obrigatoriamente para o JoinGatewayDefinition que fecha o fan-out — o Navigator lança RuntimeException no deploy/execução se esse campo estiver ausente.
  • JoinGatewayDefinition.sourceSplitId é informativo (documenta de qual split o join se origina), mas a reconciliação real de ramos concluídos é feita via pendingBranchIds na ExecutableTask do tipo JOIN_GATEWAY — coberto em Execução Síncrona e Assíncrona.

Boundary events e attachedToRef

Timers de borda (InterruptiveTimerEventDefinition, NonInterruptiveTimerEventDefinition) e o handler de erro (ErrorHandlerDefinition) implementam BoundaryEventDefinition, que exige attachedToRef — o id do nó ao qual o evento está anexado (tipicamente um EXTERNAL_TASK de longa duração ou um EXECUTABLE_TASK):

public sealed interface BoundaryEventDefinition extends FlowNodeDefinition
permits InterruptiveTimerEventDefinition, NonInterruptiveTimerEventDefinition, ErrorHandlerDefinition {
String attachedToRef();
}

No JSON, a associação é declarada duas vezes por razões de navegabilidade do editor: o nó pai lista os boundary events em boundaryEventIds (ou array embutido boundaryEvents, dependendo de como o exportador estrutura o documento), e o próprio boundary event referencia attachedToRef de volta para o pai.

Referência rápida de todos os tipos de nó

TipoInterface adicionalExecuta lógica Java?Bloqueia até evento externo?
DEFAULT_START_EVENTNãoNão
DEFAULT_END_EVENTNãoNão
EXECUTABLE_TASKExecutableSim (TaskHandler)Não
EXTERNAL_TASKWaitStateNão (delega a worker externo)Sim
EXCLUSIVE_GATEWAYOpcional (AnswerProvider se providerType: BEAN)Não
PARALLEL_GATEWAYNãoNão
JOIN_GATEWAYNãoSim (até todos os ramos concluírem)
BOUNDARY_INTERRUPTIVE_TIMERBoundaryEventDefinitionOpcional (DueDateProvider se providerType: BEAN)Sim (até o timer disparar)
BOUNDARY_NON_INTERRUPTIVE_TIMERBoundaryEventDefinitionIdemSim, mas sem interromper o nó pai
BOUNDARY_ERROR_HANDLERBoundaryEventDefinitionNãoNão
EVENT_CATCHERWaitStateOpcional (CorrelationKeysProvider se providerType: BEAN)Sim (até correlateMessage com a chave certa)
BOUNDARY_INTERRUPTIVE_CATCH_EVENTBoundaryEventDefinitionOpcional (CorrelationKeysProvider se providerType: BEAN)Sim (até correlateMessage com a chave certa, ou o nó pai terminar antes)
TIMER_TASKOpcional (DueDateProvider se providerType: BEAN)Sim (até o timer disparar)
EVENT_THROWERNão (comportamento embutido no motor, não delega a TaskHandler)Não (lança e segue — não bloqueia quem lançou)
CALL_ACTIVITY_COORDINATORNão (spawna instância(s) filha(s), não roda handler)Sim (até todas as instâncias filhas concluírem)