Existem muitas soluções que comprometem mais do que eu estou confortável. É verdade que, se o seu caso de uso for complexo, como movimentar dinheiro entre bancos diferentes, alternativas mais agradáveis podem ser impossíveis. Mas vejamos o que podemos fazer no cenário comum, onde o uso de microsserviços interfere em nossas transações de banco de dados em potencial.
Opção 1: Evite a necessidade de transações, se tudo isso for possível
Óbvio e mencionado antes, mas ideal se pudermos gerenciá-lo. Os componentes realmente pertencem ao mesmo microsserviço? Ou podemos redesenhar o (s) sistema (s) para que a transação se torne desnecessária? Talvez aceitar a não-transacionalidade seja o sacrifício mais acessível.
Opção 2: usar uma fila
Se houver certeza suficiente de que o outro serviço terá êxito no que quer que ele faça, podemos chamá-lo através de alguma forma de fila. O item na fila não será coletado até mais tarde, mas podemos garantir que o item esteja na fila .
Por exemplo, digamos que desejamos inserir uma entidade e enviar um email como uma única transação. Em vez de chamar o servidor de correio, enfileiramos o email em uma tabela.
Begin transaction
Insert entity
Insert e-mail
Commit transaction
Uma desvantagem clara é que vários microsserviços precisarão acessar a mesma tabela.
Opção 3: faça o trabalho externo por último, pouco antes de concluir a transação
Essa abordagem baseia-se na suposição de que é muito improvável que a confirmação da transação falhe.
Begin transaction
Insert entity
Insert another entity
Make external call
Commit transaction
Se as consultas falharem, a chamada externa ainda não foi realizada. Se a chamada externa falhar, a transação nunca será confirmada.
Essa abordagem vem com as limitações de que só podemos fazer uma chamada externa e isso deve ser feito por último (ou seja, não podemos usar o resultado em nossas consultas).
Opção 4: criar coisas em um estado pendente
Conforme publicado aqui , podemos fazer com que vários microsserviços criem componentes diferentes, cada um em um estado pendente, sem transação.
Qualquer validação é realizada, mas nada é criado em um estado definitivo. Depois que tudo foi criado com sucesso, cada componente é ativado. Geralmente, essa operação é tão simples e as chances de algo dar errado são tão pequenas que podemos até preferir fazer a ativação sem transação.
A maior desvantagem é provavelmente o fato de termos de explicar a existência de itens pendentes. Qualquer consulta de seleção precisa considerar se deve incluir dados pendentes. A maioria deveria ignorá-lo. E as atualizações são outra história.
Opção 5: deixe o microsserviço compartilhar sua consulta
Nenhuma das outras opções faz isso por você? Então vamos ficar pouco ortodoxos .
Dependendo da empresa, este pode ser inaceitável. Estou ciente. Isso não é ortodoxo. Se não for aceitável, siga outra rota. Mas se isso se encaixa na sua situação, resolve o problema de maneira simples e poderosa. Pode ser apenas o compromisso mais aceitável.
Existe uma maneira de transformar consultas de vários microsserviços em uma transação simples e única do banco de dados.
Retorne a consulta, em vez de executá-la.
Begin transaction
Execute our own query
Make external call, receiving a query
Execute received query
Commit transaction
Em termos de rede, cada microsserviço precisa ser capaz de acessar cada banco de dados. Lembre-se disso, também em relação à escala futura.
Se os bancos de dados envolvidos na transação estiverem no mesmo servidor, essa será uma transação regular. Se eles estiverem em servidores diferentes, será uma transação distribuída. O código é o mesmo, independentemente.
Recebemos a consulta, incluindo seu tipo de conexão, seus parâmetros e sua cadeia de conexão. Podemos agrupá-lo em uma elegante classe executável de comando, mantendo o fluxo legível: a chamada de microsserviço resulta em um comando que executamos como parte de nossa transação.
A cadeia de conexão é o que o microsserviço de origem nos fornece; portanto, para todos os efeitos, a consulta ainda é considerada executada por esse microsserviço. Estamos apenas encaminhando-o fisicamente através do microsserviço do cliente. Isso faz alguma diferença? Bem, vamos colocar na mesma transação com outra consulta.
Se o compromisso for aceitável, essa abordagem nos fornecerá a transacionalidade direta de um aplicativo monolítico, em uma arquitetura de microsserviço.