Entendendo os estados genéricos de um processo
Quando você desenha um fluxo de trabalho ou implementa um motor de workflows, precisa mapear pelo menos os estados genéricos de um processo são bem definidos, senão acaba criando bug após bug sem saber o que acontece quando algo dá errado. Eu passei dois anos tentando consertar processos que entravam em estados fantasmas, então vou explicar isso de forma prática, sem enrolação.
os estados genéricos de um processo são
A base é simples. Todo processo, independente da ferramenta que você usar — Camunda, Flowable, uma engine caseira ou até um scriptPython mal estruturado — passa por um conjunto de estados fundamentais. Na maioria dos casos, são cinco a sete estados no total. Se o seu processo tem mais que isso, provavelmente você está complicando sem necessidade. Os estados mais comuns que eu vejo na prática são:
Iniciado (Started/Initialized): O processo foi criado e entrou no sistema. Nesse momento, as variáveis de contexto são populadas e a primeira tarefa é despachada. É o estado que todo mundo erra. As pessoas esquecem de validar os dados de entrada antes de marcar o processo como iniciado. Eu já vi casos onde um formulário vinha com campos nulos e o motor simplesmente avançava para a próxima etapa. A solução é simples: adicione uma validação obrigatória no hook de início e rejeite o processo se os dados essenciais faltarem. Não deixe para validar depois. Em execução (Running/Active): O processo está ativo, as tarefas estão sendo processadas e o fluxo progride normalmente. A parte chata é que esse estado pode significar coisas diferentes dependendo da engine. Em sistemas com múltiplos threads, um processo pode estar "em execução" enquanto espera por uma chamada HTTP externa, o que parece trivial mas causa problemas reais de monitoramento. Se você precisa saber quantas instâncias estão realmente ativas versus bloqueadas em I/O, precisará de métricas específicas, não apenas do estado do processo.
Pausado (Paused/Suspended): O processo foi interrompido deliberadamente. Pode ser por uma mensagem de espera, um timer configurado, ou uma decisão manual do operador. Esse é um dos estados mais negligenciados em termos de gestão. Processos pausados acumulam. Eu trabalhei num projeto onde tínhamos mais de três mil processos suspensos acumulados há meses e ninguém sabia. O sistema estava lento e ninguém conseguia identificar o gargalo. A dica prática: implemente um watchdog que alerta quando processos ficam suspensos por mais de X horas e crie rotinas de limpeza periódica. Completo (Completed/Done): O processo atingiu seu objetivo final e foi encerrado com sucesso. Parece óbvio, mas há uma diferença importante entre "processo finalizado" e "processo completo". Um processo pode ser finalizado porque teve um erro irreversível. Certifique-se de que o estado "completo" só é alcançado quando todas as condições de saída foram satisfeitas e os dados de resultado foram persistidos corretamente. Eu já perdi dias rastreando dados corrompidos porque o processo marcava como completo antes de salvar o resultado no banco.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Cancelado (Cancelled/Terminated): O processo foi interrompido antes do término normal, seja por decisão do usuário, timeout ou política de negócio. Aqui entra um problema que poucas pessoas consideram: o cancelamento precisa limpar tudo o que foi feito durante a execução. Variáveis de contexto, recursos alocados, filas de mensagens consumidas. Se o seu motor não lida com rollback de forma consistente, você vai ter dados inconsistentes espalhados pelo sistema. Em erro (Error/Faulted): Algo deu errado durante a execução e o processo precisa de intervenção manual ou de uma política de retry. Esse estado merece atenção especial porque é onde a maioria dos sistemas falha. Processos em erro são frequentemente ignorados até que se acumulem a ponto de causar sérios problemas. Configure alertas automáticos e um SLA de resolução. Eu pessoalmente configurei um sistema onde processos em erro por mais de duas horas acionavam uma notificação obrigatória para a equipe de suporte.
Como implementar isso na prática
A parte mais importante é garantir transições válidas entre esses estados. Você precisa de uma máquina de estados finitos bem definida. O erro mais comum que eu vejo é permitir transições impossíveis, como ir de "completo" para "em execução" ou de "cancelado" para "pausado". Isso acontece quando alguém adiciona funcionalidade nova sem revisar as regras de transição existentes. Use uma tabela de transições. Liste todos os estados possíveis e, para cada par estado-entrada, defina exatamente qual ação é permitida e qual é proibida. Quando eu comecei a fazer isso sistematicamente, reduzi bugs de estado em cerca de oitenta por cento. O impacto foi imediato e mensurável.
Outro ponto que as pessoas subestimam é o logging de transições. Cada mudança de estado deve ser registrada com timestamp, usuário ou sistema responsável, e os dados de contexto naquele momento. Sem isso, quando algo der errado — e vai dar — você vai perder horas tentando reconstruir o que aconteceu. Um problema específico que encontrei foi com processos que tinham timers configurados. Quando um timer disparava, o processo era movido para o próximo estado, mas em alguns casos o timer disparava duas vezes devido a problemas de sincronização de horário nos servidores. A solução foi implementar um mechanismo de lock otimista nas transições dependentes de tempo, com versionamento das requisições. O overhead foi mínimo — cerca de dez milisegundos adicionais por transição — mas eliminou completamente aquele problema.
O que não funciona
Não use apenas um campo booleano para representar o estado. Eu vi muitos desenvolvedores usando isActive ou isCompleted como flags separadas. Isso leva a estados impossíveis como um processo que é ao mesmo tempo ativo e completado. Use sempre um enum ou inteiro que represente um único estado por vez. Também não ignore o estado inicial. Alguns frameworks assumem que o processo começa automaticamente em execução. Se você não configurar o estado inicial explicitamente, pode ter problemas de consistência quando o processo precisa de uma validação prévia antes de começar a rodar de fato.
A persistência dos estados também precisa ser planejada. Processos de longa duração que ficam segundos ou minutos em estados de pausa precisam de seu estado salvo de forma durável. Se o servidor cair enquanto o processo está em memória, você perde o estado. Use persistência imediata para cada transição de estado, não aguarde o final do processo para salvar.