DDD, Saga e fornecimento de eventos: uma ação de compensação pode ser simplesmente uma exclusão no armazenamento de eventos?


15

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:

  1. 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.
  2. Essas raízes agregadas podem operar completamente de forma autônoma (boa separação de preocupações, grande escalabilidade etc.)
  3. 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)
  4. 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.
  5. 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)
  6. 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)
  7. 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.
  8. 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.
  9. 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)
  10. 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)
  11. 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.

Respostas:


9

Você não deve excluir os eventos do seu armazenamento de eventos. Estes representam algo que aconteceu. Se algo acontecer agora, você também deve saber, portanto, adicione um evento que forçará seu agregado a retornar a um estado anterior. É uma pena excluir informações do seu banco de dados.

pense no exemplo do carrinho de greg young e nos itens removidos. Pode ser que amanhã as informações da ação compensatória tenham algum valor.

Quanto à saga, tudo está correto, tanto quanto eu me conheço. Você deve pensar na saga como uma máquina de estado. Faz apenas isso.

É um comando que a saga está emitindo para dizer ao agregado para fazer alguma coisa. Desta ação, haverá um evento. Esse evento pode ser a ação corretiva de que você precisa ou pode precisar ser desnormalizado em uma exibição para que algum usuário o veja para decidir o que fazer.

Depende das suas regras de negócios. Existe uma solução fácil: a raiz agregada sabe que, nesse caso, você faz isso ou a escolha é muito complexa para ser feita programaticamente (o custo de desenvolvimento é muito alto) e, portanto, você pode propor isso a algum usuário, que pode escolher entre ações diferentes. Tudo depende do contexto da ação compensatória. São regras de negócios puras. O que devemos fazer neste caso ou nesse caso. Isso é algo para perguntar ao seu especialista em domínio e, em seguida, escolha com ele se é melhor desenvolver uma solução automática ou se a solução é perguntar ao usuário Ronald R., porque ele é o único a responder a essa pergunta normalmente.


Como o agregado saberia para qual estado reverter? Seria permitido consultar a loja de eventos ou algo assim?
Geert-Jan

Não deve reverter, mas adicionar outro evento. É um comando que a saga está emitindo para dizer ao agregado para fazer alguma coisa. Desta ação, haverá um evento.
Arthis 19/07/12

Sim eu entendo. "Reverter" provavelmente foi mal escolhido. Considere o seguinte: Talvez eu queira usar o Event Sourcing with Sagas para modelar, entre outras coisas, fluxos de publicação / aprovação de documentos. E se um editor enviar uma ação ChangeBlogBody que, no final das contas, persistir como um evento BlogBodyChanged para o Event Store. Posteriormente, por algum motivo, uma Ação de compensação é emitida. Como o Agregado saberia qual evento de compensação disparar que resulta no conteúdo do Corpo do Blog, exatamente como era antes da ação de ChangeBlogBody ser emitida?
Geert-Jan

Depende das suas regras de negócios. Existe uma solução fácil: a raiz agregada sabe que, nesse caso, você faz isso ou a escolha é muito complexa para ser feita programaticamente (o custo de desenvolvimento é muito alto) e, portanto, você pode propor isso a algum usuário, que pode escolher entre ações diferentes.
Arthis 19/07/12

Tudo depende do contexto da ação compensatória. São regras de negócios puras. O que devemos fazer neste caso ou nesse caso. Isso é algo para perguntar ao seu especialista em domínio e, em seguida, escolha com ele se é melhor desenvolver uma solução automática ou se a solução é perguntar ao usuário Ronald R., porque ele é o único a responder a essa pergunta normalmente.
Arthis 19/07/12

6

Para completar, pensei em incluir um trecho relevante de Martin Fowler sobre maneiras de reverter o estado:

Assim como os eventos se apresentam para a frente, também costuma ser útil para eles se inverterem.

A reversão é a mais direta quando o evento é lançado na forma de uma diferença. Um exemplo disso seria "adicionar US $ 10 à conta de Martin" em vez de "definir a conta de Martin como US $ 110". No primeiro caso, posso reverter subtraindo apenas US $ 10, mas no segundo caso não tenho informações suficientes para recriar o valor passado da conta.

Se os eventos de entrada não seguirem a abordagem da diferença, o evento deve garantir que armazene tudo o necessário para a reversão durante o processamento. Você pode fazer isso armazenando os valores anteriores em qualquer valor alterado ou calculando e armazenando diferenças no evento.

De: http://martinfowler.com/eaaDev/EventSourcing.html


1

Conceitualmente:

  • Evento é algo que aconteceu. O passado não pode ser alterado.
  • Comando é algo a se fazer. O comando pode não acontecer (pode ser rejeitado).

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":

  • E se o último evento não for o que deve ser excluído? E se outros eventos acontecessem após o apagamento? Esses eventos também precisam ser alterados (como seu estado base mudaria ao excluir o evento antes deles).
  • E se o evento foi enviado ao sistema externo? Você pode não ter acesso para corrigir seu estado além de enviar outro 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.


0

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:

try {
    newEvents = processMycommand(myCommand)
    for (Event newEvent : newEvents)
        EventStore.insertEvent(newEvent);
} catch (Exception e) {
    EventStore.rollback();
}

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.


0

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:

insira a descrição da imagem aqui 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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.