Essa é uma pergunta clássica que me foi feita durante uma entrevista recentemente Como chamar vários serviços da Web e ainda preservar algum tipo de tratamento de erro no meio da tarefa. Hoje, na computação de alto desempenho, evitamos confirmações em duas fases. Eu li um artigo há muitos anos sobre o que foi chamado de "modelo Starbuck" para transações: pense no processo de pedido, pagamento, preparação e recebimento do café que você pede na Starbuck ... Eu simplifico demais as coisas, mas um modelo de confirmação em duas fases seria sugira que todo o processo seja uma transação única para todas as etapas envolvidas até você receber seu café. No entanto, com esse modelo, todos os funcionários esperariam e parariam de trabalhar até você tomar seu café. Você vê a foto?
Em vez disso, o "modelo Starbuck" é mais produtivo, seguindo o modelo de "melhor esforço" e compensando os erros no processo. Primeiro, eles garantem que você pague! Depois, há filas de mensagens com seu pedido anexado ao copo. Se algo der errado no processo, como você não recebeu seu café, não foi o que pediu, etc., entramos no processo de compensação e garantimos que você obtém o que deseja ou o devolve. Este é o modelo mais eficiente para aumentar a produtividade.
Às vezes, a starbuck está desperdiçando um café, mas o processo geral é eficiente. Existem outros truques para pensar quando você cria seus serviços da Web, como projetá-los de uma maneira que eles podem ser chamados inúmeras vezes e ainda assim fornecem o mesmo resultado final. Então, minha recomendação é:
Não fique muito bem ao definir seus serviços da Web (não estou convencido sobre o hype de microsserviços que acontece hoje em dia: muitos riscos de ir longe demais);
Async aumenta o desempenho; portanto, prefira ser assíncrono, envie notificações por email sempre que possível.
Crie serviços mais inteligentes para torná-los "recuperáveis" várias vezes, processando com um uid ou taskid que seguirá o pedido até o final, validando as regras de negócios em cada etapa;
Use filas de mensagens (JMS ou outras) e desvie para processadores de tratamento de erros que aplicarão operações à "reversão" aplicando operações opostas. A propósito, trabalhar com ordem assíncrona exigirá algum tipo de fila para validar o estado atual do processo, então considere isso;
Por último, (como isso pode não acontecer com frequência), coloque-o em uma fila para processamento manual de erros.
Vamos voltar com o problema inicial que foi postado. Crie uma conta e crie uma carteira e verifique se tudo foi feito.
Digamos que um serviço da Web seja chamado para orquestrar toda a operação.
O pseudo-código do serviço da web ficaria assim:
Ligue para o microsserviço de criação de conta, passe algumas informações e um ID de tarefa exclusivo 1.1 O microsserviço de criação de conta verificará primeiro se essa conta já foi criada. Um ID de tarefa está associado ao registro da conta. O microsserviço detecta que a conta não existe e, portanto, a cria e armazena o ID da tarefa. NOTA: este serviço pode ser chamado 2000 vezes, sempre executará o mesmo resultado. O serviço responde com um "recibo que contém informações mínimas para executar uma operação de desfazer, se necessário".
Ligue para a criação do Wallet, fornecendo o ID da conta e o ID da tarefa. Digamos que uma condição não seja válida e a criação da carteira não possa ser executada. A chamada retorna com um erro, mas nada foi criado.
O orquestrador é informado do erro. Ele sabe que precisa interromper a criação da conta, mas não fará isso sozinho. Ele solicitará que o serviço de carteira faça isso passando seu "recibo mínimo de desfazer" recebido no final da etapa 1.
O serviço de conta lê o recebimento de desfazer e sabe como desfazer a operação; o recebimento de desfazer pode até incluir informações sobre outro microsserviço que ele poderia ter chamado para fazer parte do trabalho. Nessa situação, o recebimento de desfazer pode conter o ID da conta e possivelmente algumas informações adicionais necessárias para executar a operação oposta. No nosso caso, para simplificar, digamos que é simplesmente excluir a conta usando seu ID.
Agora, digamos que o serviço da Web nunca tenha recebido o sucesso ou a falha (neste caso) de que o desfazer da criação da conta foi realizado. Ele simplesmente chamará o serviço de desfazer da conta novamente. E esse serviço normalmente nunca falha, porque seu objetivo é que a conta não exista mais. Por isso, verifica se existe e vê que nada pode ser feito para desfazê-lo. Portanto, retorna que a operação é um sucesso.
O serviço da web retorna ao usuário que a conta não pôde ser criada.
Este é um exemplo síncrono. Poderíamos ter gerenciado de maneira diferente e colocado o caso em uma fila de mensagens direcionada ao suporte técnico, se não quisermos que o sistema recupere completamente o erro ". Já vi isso sendo realizado em uma empresa onde não é suficiente ganchos podem ser fornecidos ao sistema de back-end para corrigir situações.O suporte técnico recebeu mensagens contendo o que foi executado com êxito e tinha informações suficientes para corrigir coisas, assim como nosso recibo de desfazer poderia ser usado de uma maneira totalmente automatizada.
Eu realizei uma pesquisa e o site da microsoft tem uma descrição padrão para essa abordagem. É chamado de padrão de transação compensadora:
Padrão de transação de compensação