BOUNDARY_INTERRUPTIVE_CATCH_EVENT — Cancelamento por Correlação
Pense num pedido de comida por aplicativo enquanto o restaurante prepara. Você pode cancelar pelo número do pedido — não precisa saber qual funcionário está mexendo a panela, nem em que etapa está. Se o cancelamento chega antes de o pedido sair, a cozinha para e o fluxo vai para "pedido cancelado", não para "pedido entregue". Onde a analogia quebra: se o pedido já saiu para entrega, o botão de cancelar some — no Kikwiflow, o mesmo: chegou a correlação depois de a tarefa concluir normalmente, e a chave simplesmente não é mais encontrada.
Um BOUNDARY_INTERRUPTIVE_CATCH_EVENT modela "esta tarefa pode ser cancelada por um evento externo
de negócio" — o mesmo conceito de correlação da
EVENT_CATCHER, só que como um evento de borda
anexado a uma tarefa, não como um passo do fluxo principal. É a versão "por correlação" do
BOUNDARY_INTERRUPTIVE_TIMER:
em vez de cancelar a tarefa quando um prazo vence, ele cancela quando uma chave de negócio
chega via KikwiflowEngine.correlateMessage(...).
{
"id": "COLETAR_DADOS",
"name": "Coletar Dados",
"type": "EXTERNAL_TASK",
"boundaryEventIds": ["CANCEL_CATCH"],
"outgoing": [ { "targetNodeId": "END_EVENT_SUCCESS" } ]
},
{
"id": "CANCEL_CATCH",
"name": "Cancelamento Externo",
"type": "BOUNDARY_INTERRUPTIVE_CATCH_EVENT",
"attachedToRef": "COLETAR_DADOS",
"providerType": "STATIC",
"staticKey": "cancelar-task-15649234",
"outgoing": [ { "targetNodeId": "END_EVENT_CANCELLED" } ]
}
Quando alguém chama kikwiflowEngine.correlateMessage("cancelar-task-15649234", variaveis, identityContext), COLETAR_DADOS é cancelada e o fluxo segue para END_EVENT_CANCELLED — nunca
para o outgoing de COLETAR_DADOS.
Referência de campos
| Campo | Obrigatório? | Descrição |
|---|---|---|
id | Sim | Identificador único. É o valor que deve aparecer em boundaryEventIds do nó pai. |
name / description | Não | Rótulo e texto livre. |
attachedToRef | Sim | id do nó pai (EXTERNAL_TASK ou TIMER_TASK). Os dois lados devem se referenciar mutuamente. |
providerType | Sim | STATIC | VARIABLE | BEAN | TEMPLATE — as mesmas 4 estratégias do EVENT_CATCHER, sempre resolvendo exatamente 1 chave. |
staticKey | Só se STATIC | Chave fixa de cancelamento. |
providerVariable | Só se VARIABLE | Nome da variável (valor escalar — nunca lista). |
providerBean | Só se BEAN | Bean CorrelationKeysProvider que devolve exatamente 1 item. |
correlationTemplates | Só se TEMPLATE | 1 entrada (não há modo GROUP aqui). |
keyPrefix / keySuffix | Não | Só com VARIABLE. |
outgoing | Sim (1 entrada) | Para onde o fluxo vai quando este evento dispara. |
Campos que este nó não tem (ao contrário do EVENT_CATCHER): catchType, matchPolicy,
boundaryEventIds. commitBefore/commitAfter são aceitos no JSON mas sem efeito observável.
Onde pode ser anexado
Nó pai (attachedToRef) | Suportado? |
|---|---|
EXTERNAL_TASK | Sim |
TIMER_TASK | Sim — ver TIMER_TASK — Boundary events |
EXECUTABLE_TASK | Não — bloqueado na implantação |
EVENT_CATCHER | Não |
:::danger Bloqueado em DeployValidator: boundary interruptivo em EXECUTABLE_TASK
Um EXECUTABLE_TASK executa seu handler de forma síncrona, na mesma thread que o adquiriu — não há
como interrompê-lo de fora a meio caminho sem risco de um efeito colateral real (uma chamada de API,
por exemplo) já ter acontecido, sem forma de desfazê-lo. Anexar a um EXECUTABLE_TASK, a um
EVENT_CATCHER, ou a qualquer nó não suportado é rejeitado no momento da implantação
(InvalidProcessDefinitionException). EXTERNAL_TASK e TIMER_TASK são seguros porque nenhum dos
dois roda handler síncrono com efeito colateral.
:::
:::danger No máximo um evento de borda interruptivo por nó pai
Se o mesmo nó pai tiver dois eventos de borda interruptivos anexados (ex.: um
BOUNDARY_INTERRUPTIVE_TIMER de SLA e este BOUNDARY_INTERRUPTIVE_CATCH_EVENT de cancelamento)
e um deles disparar primeiro, o outro não é cancelado automaticamente — continua existindo,
apontando para um nó pai que já não existe. Até isso ser resolvido, use no máximo um evento de
borda interruptivo por nó pai.
:::
Exemplo com VARIABLE
{
"id": "CANCEL_CATCH",
"type": "BOUNDARY_INTERRUPTIVE_CATCH_EVENT",
"attachedToRef": "PROCESSAR_DADOS",
"providerType": "VARIABLE",
"providerVariable": "taskId",
"keyPrefix": "CANCELAR_TASK_",
"outgoing": [ { "targetNodeId": "END_EVENT_CANCELLED" } ]
}
Se taskId = "99887766", a chave resolvida é "CANCELAR_TASK_99887766".
Exemplo anexado a um TIMER_TASK
Cancelar a espera de um TIMER_TASK antes do prazo vencer — "aguardar até X,
mas permitir que alguém encerre a espera antes":
{
"id": "WAIT_SLA",
"type": "TIMER_TASK",
"providerType": "STATIC",
"staticValue": "PT24H",
"boundaryEventIds": ["CANCEL_CATCH"],
"outgoing": [ { "targetNodeId": "AFTER_TIMER" } ]
},
{
"id": "CANCEL_CATCH",
"type": "BOUNDARY_INTERRUPTIVE_CATCH_EVENT",
"attachedToRef": "WAIT_SLA",
"providerType": "STATIC",
"staticKey": "cancelar-timer-task-sla",
"outgoing": [ { "targetNodeId": "END_EVENT_CANCELLED" } ]
}
O que acontece ao cancelar
- Alguém chama
correlateMessage(chave, variaveis, identityContext)com a chave configurada. - O nó pai (
attachedToRef) é cancelado — desaparece da lista de tarefas ativas da instância. - O fluxo continua pelo
outgoingdeste evento de borda, nunca pelooutgoingdo nó pai. - Se o cancelamento chega depois de o nó pai já ter concluído normalmente, a chave não é mais
encontrada —
correlateMessagelançaTaskNotFoundException(mesma proteção de idempotência doEVENT_CATCHER).
Validações
Mesma família de erros do EVENT_CATCHER (compartilham o mecanismo de resolução de chave), com uma
diferença: como não há modo GROUP, qualquer resolução com mais de 1 item lança
IllegalStateException. Todas as demais condições (providerType/campo nulo, variável ausente,
BEAN sem bean registrado, TEMPLATE referenciando variável inexistente, lista vazia) lançam
IllegalStateException ao alcançar o nó pai pela primeira vez — é aí que a chave é resolvida e
o evento de borda é criado. attachedToRef apontando para um tipo de nó não suportado é
InvalidProcessDefinitionException no momento da implantação.
Quando usar / quando não usar
| Se você precisa de... | Use |
|---|---|
| Cancelar por prazo vencido | BOUNDARY_INTERRUPTIVE_TIMER |
| Cancelar por uma chave de negócio externa, sem prazo | BOUNDARY_INTERRUPTIVE_CATCH_EVENT (este nó) |
| Aguardar uma chave de negócio como o próprio próximo passo, não como cancelamento | EVENT_CATCHER modo STANDALONE |
| Cancelar uma espera GROUP inteira por prazo | BOUNDARY_INTERRUPTIVE_TIMER anexado ao EVENT_CATCHER |
| Cancelar uma espera GROUP inteira por correlação | Não suportado ainda |
Não anexe a um EXECUTABLE_TASK (o deploy recusa). Não combine com outro boundary
interruptivo no mesmo nó pai enquanto a limitação acima existir.
Próximo passo
Continue para TIMER_TASK — Espera por Prazo no Fluxo Principal.