Pergunta

Temos um fluxo de trabalho da máquina de estado para manter o estado de um aplicativo enviado por um usuário. Um dos problemas que estou tendo está relacionado ao término do fluxo de trabalho. Em um dos estados, eu tinha um bug. Quando o aplicativo atingiu esse estado, ele lançou uma exceção e, como resultado, o evento de rescisão do fluxo de trabalho foi chamado e a instância de fluxo de trabalho específica foi removida do banco de dados de persistência. Portanto, não consigo mais carregar essa instância do fluxo de trabalho. Eu esperava, se houver um erro em um dos estados, uma exceção seria lançada (para que saibamos qual é o problema), mas toda a instância do fluxo de trabalho não deve desaparecer. A atividade do manipulador de falhas pode garantir que o fluxo de trabalho não termine. Além disso, existe uma maneira, quando o evento de encerramento é chamado, as instâncias não são removidas da loja de persistência.

Obrigado por qualquer ajuda/sugestões.

Foi útil?

Solução

Quando uma exceção é lançada em um fluxo de trabalho, a exceção efetivamente "borbulha" através dos ancestrais de atividades até que seja:

  1. Tratado por uma atividade de manipulador de falhas
  2. Atinge a atividade raiz (ou seja: o próprio fluxo de trabalho), momento em que o fluxo de trabalho será encerrado.

É uma boa prática criar manipuladores de falhas para todas as exceções possíveis nos lugares certos. Usando uma atividade de manipulador de falhas, você pode recuperar a instância do fluxo de trabalho e definir efetivamente a máquina de estado em um estado utilizável, em vez de terminá -lo.

Depois que um fluxo de trabalho terminou, é inutilizável, portanto, não haveria benefício em mantê -lo no armazenamento de persistência assim que o término ocorrer, e é por isso que ele é removido. Então você pode ver, a chave é impedir que ela termine inesperadamente.

Uma dica final. Quando um fluxo de trabalho termina, a exceção que causou o término é enviada aos ouvintes de eventos como a propriedade de exceção do objeto WorkflowEnminedEventArgs. Eu absolutamente recomendaria ter algum tipo de mecanismo de log para pegá -lo e gerá -lo em algum lugar, para que, se você experimentar bugs no futuro que, por algum motivo, não é capturado, será muito mais fácil rastreá -los.

Outras dicas

Criei um serviço de persistência de fluxo de trabalho SQL personalizado que impede que o fluxo de trabalho termine - deixando assim o fluxo de trabalho no estado anterior antes da transição que causou o erro:

public class CustomSqlWorkflowPersistenceService : SqlWorkflowPersistenceService
    {
        public CustomSqlWorkflowPersistenceService (string connectionString) : base(connectionString)
        {
        }

        public CustomSqlWorkflowPersistenceService (NameValueCollection parameters) : base(parameters)
        {
        }

        public CustomSqlWorkflowPersistenceService (string connectionString, bool unloadOnIdle, TimeSpan instanceOwnershipDuration, TimeSpan loadingInterval) : base(connectionString, unloadOnIdle, instanceOwnershipDuration, loadingInterval)
        {
        }

        protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock)
        {
            WorkflowStatus workflowStatus = GetWorkflowStatus(rootActivity);
            if (workflowStatus == WorkflowStatus.Terminated)
            {
                string workflowError = GetSuspendOrTerminateInfo(rootActivity);
                if (!string.IsNullOrEmpty(workflowError))
                {
                    string error = string.Format("Workflow terminated, forcing an abort! {0}", workflowError);
                    throw new Exception(error);
                }
            }
            base.SaveWorkflowInstanceState(rootActivity, unlock);
        }
    }

Obviamente, isso será uma dor se você quiser forçar um WF a terminar, mas tenho certeza de que você pode contornar isso.

Estou usando o SQLWorkFlowPerSistence, como uma correção para isso, fiz o abaixo:

No 'WorkflowPerSistence' DB, temos o SP 'insertInstancestate', que exclui a instância. Eu comentei o código que exclui a instância.

Parece que está funcionando, mas não tenho certeza se essa é a maneira correta.

Parte do SP é mostrada abaixo, que eu mudei.

IF
@status=1 OR @status=3          
    BEGIN      

/* DELETE FROM [dbo].[InstanceState] WHERE uidInstanceID=@uidInstanceID AND ((ownerID = @ownerID AND ownedUntil>=@now) 
 OR (ownerID IS NULL AND @ownerID IS NULL ))          
*/
    END  
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top