Eu percebo que a pergunta acima provavelmente levanta alguns 'what ??', mas deixe-me tentar explicar:
Estou tentando entender alguns conceitos relacionados, basicamente o padrão Saga ( http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf ) em combinação com a fonte de eventos (um conceito DDD : http://en.wikipedia.org/wiki/Domain-driven_design )
Uma boa publicação que reúne tudo isso: https://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-ii-of-ii/
Estou chegando à pergunta em um minuto, mas acho que tenho que tentar resumir o que entendo primeiro (o que pode estar errado, por isso, corrija se for esse o caso), pois isso pode ter um impacto sobre o motivo de eu estar fazendo a pergunta para começar:
- O padrão Saga é um tipo de intermediário que fornece uma ação (usuário final, automatizado etc. essencialmente qualquer coisa que altere dados) divide essa ação nas atividades de negócios e envia cada uma dessas atividades como mensagens para um barramento de mensagens que por sua vez, envia-o para as respectivas raízes agregadas a serem tratadas.
- Essas raízes agregadas podem operar completamente de forma autônoma (boa separação de preocupações, grande escalabilidade etc.)
- Uma instância do Saga em si não contém nenhuma lógica comercial, contida nas raízes agregadas às quais envia atividades. A única 'lógica' contida na Saga é a lógica do 'processo' (geralmente implementada como uma máquina de estado), que determina com base nas ações recebidas (bem como nos eventos de acompanhamento) o que fazer (ou seja, quais atividades enviar)
- Os padrões Saga implementam um tipo de padrão de transação distribuída. Ou seja: quando uma das raízes agregadas (que novamente trabalha autonomamente, sem o conhecimento de outras existências) falha, toda a ação pode ter que ser revertida.
- Isso é implementado com todas as raízes agregadas, após a conclusão do relatório de atividades da Saga. (Em caso de sucesso, bem como erro)
- Caso todas as raízes agregadas retornem um sucesso, a máquina de estado interna se a Saga determinar o que fazer em seguida (ou decidir que está pronto)
- Em caso de falha, a Saga emite para todas as raízes agregadas que participaram da última ação a chamada Ação de compensação, ou seja: uma ação para desfazer a última ação que cada uma das raízes agregadas fez.
- Isso pode ser simplesmente fazer um 'menos 1 voto' se a ação for "mais 1 voto", mas pode ser mais complicado como restaurar um post do blog para a versão anterior.
- A terceirização de eventos (consulte a postagem do blog que combina os dois) visa externalizar salvando os resultados de cada uma das atividades que cada uma das raízes agregadas realiza em um Armazenamento de Eventos centralizado (as alterações são chamadas de 'eventos' neste contexto)
- Esse armazenamento de eventos é a 'versão única da verdade' e pode ser usado para reproduzir o estado de todas as entidades simplesmente iterando os eventos armazenados (essencialmente como um log de eventos)
- Combinar os dois (ou seja: deixar que as raízes agregadas usem a Origem de Eventos para terceirizar salvando suas alterações antes de relatar a Saga) oferece muitas possibilidades interessantes, uma das quais diz respeito à minha pergunta ...
Eu senti que precisava tirar isso do meu ombro, já que é muito para entender de uma só vez. Dado este contexto / mentalidade (novamente, corrija se estiver errado)
a pergunta: quando uma raiz agregada recebe uma Ação de compensação e se essa raiz agregada terceiriza suas alterações de estado usando a Origem de eventos, a Ação de compensação em todas as situações não seria apenas uma exclusão do último evento no armazenamento de eventos Raiz Agregada? (Supondo que a implementação persistente permita exclusões)
Isso faria muito sentido para mim (e seria outro grande benefício dessa combinação), mas como eu disse, eu poderia estar fazendo essas suposições com base em um entendimento incorreto / incompleto desses conceitos.
Espero que isso não fique muito longo.
Obrigado.
fonte
Para completar, pensei em incluir um trecho relevante de Martin Fowler sobre maneiras de reverter o estado:
De: http://martinfowler.com/eaaDev/EventSourcing.html
fonte
Conceitualmente:
Só podemos alterar nosso estado futuro executando outro comando (Ação de compensação) que deve resultar em eventos alterando o estado do aplicativo.
Para "confundir" a pergunta, pense na frase "exclusão do último evento":
Em resumo, você não tem opção para excluir eventos dentro do padrão CQRS.
Você pode reduzir o armazenamento de eventos criando um estado de instantâneo (que se baseia em todos os eventos que levam a esse estado), mas esse aspecto físico não tem nada a ver com o conceito de evento.
fonte
Geert-Jan, também acho que a ação de compensação pode simplesmente excluir o (s) evento (s) correspondente (s). Faz sentido e mostra outro benefício do padrão de design do Event Sourcing: implementação mais fácil do padrão de design de Compensação de transações.
Alguns dizem que a exclusão do evento viola os "princípios" de fornecimento de eventos ou CQRS. Eu acho que é uma generalização limitante. Acho que não há problema em excluir um evento se ele foi criado no escopo de uma transação global que está sendo cancelada. Considere o pseudocódigo:
Suponha que seu armazenamento de eventos seja um banco de dados transacional. No pseudocódigo, você pode imaginar a situação em que inseriu o primeiro evento, mas ao tentar inserir o segundo evento, uma exceção foi lançada. O comando de reversão naturalmente reverteria a inserção do primeiro evento. Isso é razoável?
Se é razoável para uma transação de banco de dados ACID (transação com confirmação / reversão), por que não seria razoável para uma transação compensadora?
Ao executar a transação global do Saga, as alterações de dados podem ser desfeitas (por compensação). Não há necessidade de manter o evento que foi criado durante a transação porque a transação não foi concluída.
Agora, se a compensação tentar excluir um evento e esse evento não for o evento mais recente em um objeto, a exclusão não deverá ocorrer. Mas, em geral, é improvável que isso aconteça, especialmente em soluções de leitura intensiva.
fonte
Vamos brincar com o pensamento de que o armazenamento de eventos são apenas dados que você deseja salvar. Por exemplo, podemos ter um disco rígido, podemos começar do início e gravar dados nele. Toda vez que recebemos um evento, anexamos nossos dados anteriores; continuamos gravando no disco em que paramos da última vez. Quando queremos remover um evento, voltamos atrás, remova essa parte do disco e deixe um espaço. Voltar por conta própria diminui o armazenamento de eventos, mas podemos conviver com isso. Se usarmos um sistema de arquivos, isso tentará preencher a lacuna com os últimos eventos; portanto, teremos um armazenamento fragmentado lento ou poderemos desfragmentar. Nenhum deles é algo que gostamos. Se estamos falando de bancos de dados, você obtém isso se usar um banco de dados relacional em vez de um banco de dados somente anexado para armazenar seus eventos:
ref: https://cambridge-intelligence.com/bringing-time-series-data-to-life-with-keylines/
Claro. por um site normal, isso não importa, mas essas soluções são projetadas para grandes sites como Facebook, Google, etc ... Então, na verdade, a questão não faz sentido, porque como você excluiria um evento em um banco de dados apenas anexado e como seria você chama de compensação algo como construir uma máquina do tempo e voltar no tempo para mudar ou impedir um evento ???
Até onde sei. a única maneira de resolver isso é criar um novo armazenamento de eventos no qual você exclui os eventos que não deseja e depois remover o antigo armazenamento de eventos. Mas esta é uma solução extrema para remover um único evento. Se estamos falando sobre o GDPR, a única boa solução relativa que eu conheço é armazenar dados pessoais criptografados no armazenamento de eventos e remover a chave de criptografia de um banco de dados diferente.
fonte