Como implementar um gerenciador de processos na fonte de eventos


14

Estou trabalhando em um aplicativo de exemplo pequeno para aprender os conceitos de CQRS e fornecimento de eventos. Eu tenho um Basketagregado e um Productagregado que deve funcionar de forma independente.

Aqui estão alguns pseudo códigos para mostrar a implementação

Basket { BasketId; OrderLines; Address; }

// basket events
BasketCreated { BasketId; }
ItemAdded { BasketId; ProductId; Quantity }
AddItemSucceeded { BasketId; ProductId; Quantity }
AddItemRevoked { BasketId; ProductId; Quantity }
ItemRemoved { BasketId; ProductId; Quantity }
CheckedOut { BasketId; Address }

Product { ProductId; Name; Price; }

// product events
ProductReserved { ProductId; Quantity }
ProductReservationFailed { ProductId; Quantity }
ProductReservationCancelled { ProductId; Quantity; }

Os comandos são bem parecidos com os eventos, usando o nome imperativo e não o pretérito.

No momento, eles funcionam bem de forma independente. Emito um comando AddIteme ele cria um ItemAddedevento no Basketagregado que faz o que é necessário com o estado do 'Basket'. Da mesma forma, para o produto, o comando e os eventos funcionam perfeitamente.

Agora eu gostaria de combinar isso em um processo que seria algo assim (em termos de comandos e eventos que acontecem):

O gerente de processo faria o seguinte:

on BasketCreated: CreateShoppingProcess
on ItemAdded: ReserveProduct
on ProductReserved: SucceedAddingItem // does nothing, but needs to be there so that the basket knows it can check out
on ProductReservationFailed: RevokeAddItem
on RemoveItem: CancelProductReservation
on Checkout: CreateOrder // create an order and so on...

As perguntas para as quais não consegui encontrar respostas definitivas são:

  1. Preciso persistir no gerenciador de processos? Parece que sim, mas não tenho certeza
  2. Se sim, preciso salvar os eventos para o gerenciador de processos. No entanto, os eventos que está ouvindo estão vinculados aos agregados. Eu adiciono o ID do processo a esses? Tenho eventos separados apenas para o gerente de processos? Como fazer isso e manter o mais seco possível
  3. Como sei para que cesta ProductReservedservem os eventos? Tudo bem ter um BasketIdtambém, ou essas informações estão vazando?
  4. Como mantenho um relacionamento entre os eventos, como sei qual ItemAddedproduziu qual ProductReservedevento? Eu transmito um EventId? Isso parece estranho ...
  5. Devo implementar o Basketcomo um gerenciador de processos em vez de um simples agregado?

Depois de mais algumas pesquisas, cheguei a isso: uma saga é algo que mantém seus próprios eventos e ouve eventos de fora. Basicamente, é um agregado que também pode reagir a eventos que acontecem fora do próprio mundinho.

Um Gerenciador de processos trabalha com os eventos externos e envia comandos. Sua história pode ser reconstruída a partir dos eventos que ocorreram nos agregados que compartilham um identificador comum como um ID de correlação.


Parece que você está tentando codificar em seu sistema um processo formal que parafraseia um caso de uso informal existente feito de uma série de comandos. Fazendo isso, parece que você está criando vários comandos e eventos redundantes além dos existentes. Essa é a sua intenção? Qual é a necessidade dos negócios por trás da formalização das coisas como um processo no código? O que em seu domínio exige que você identifique esse processo e raciocine sobre ele como um conceito completo?
precisa

Este é um projeto totalmente elaborado, em que o objetivo é aprender a fazer com que dois agregados relativamente independentes funcionem juntos. Portanto, não há realmente nenhuma "necessidade comercial" e estou tentando evitar a redundância nesses comandos e eventos, tanto quanto possível. Daí a confusão com o gerente de processos., Porque parece que isso não deve repetir coisas que os agregados já estão manipulando. No entanto, preciso manter uma conexão entre esses dois agregados de alguma forma. Parece que o uso de causalidade e correlação pode ajudar, mas preciso testá-lo.
Ivan Pintar 06/10

Respostas:


14

Revise o que Rinat Abdullin escreveu sobre a evolução dos processos de negócios . Observe, em particular, sua recomendação para o desenvolvimento de um processo de negócios em um ambiente de mudanças rápidas - um gerente de processos é "apenas" um substituto automático para um ser humano olhando para uma tela.

Meu próprio modelo mental de gerente de processos é que é uma projeção de origem de eventos que você pode consultar para obter uma lista de comandos pendentes.

Preciso persistir no gerenciador de processos? Parece que sim, mas não tenho certeza

É um modelo de leitura. Você pode reconstruir o gerenciador de processos a partir do histórico de eventos sempre que precisar; ou você pode tratá-lo como um instantâneo que você atualiza.

Se sim, preciso salvar os eventos para o gerenciador de processos.

Não - o gerente de processos é um gerente . Não faz nada útil por si só; em vez disso, informa aos agregados para fazer o trabalho (ou seja, fazer alterações no livro de registro).

Como sei para que cesta são os eventos ProductReserved? Tudo bem ter um BasketId também ou essas informações estão vazando

Certo. Nota: na maioria dos domínios de compras "reais", você não insistiria em reservar inventário antes de processar um pedido; adiciona contenção desnecessária aos negócios. É mais provável que sua empresa queira aceitar o pedido e peça desculpas nos raros casos em que o pedido não pode ser atendido no tempo necessário.

Como mantenho um relacionamento entre os eventos, como sei qual ItemAdded produziu qual evento ProductReserved?

As mensagens têm metadados - em particular, você pode incluir um causationIdentifier (para identificar quais comandos produziram quais eventos) e um authenticationIdentifier , para rastrear geralmente a conversa.

Por exemplo, o gerenciador de processos grava seu próprio ID como o correlacionado no comando; os eventos produzidos por uma cópia do ID de correlação do comando e seu gerente de processos se inscreve em todos os eventos que possuem seu próprio ID de correlação.

Devo implementar o Basket como gerente de processos, em vez de um simples agregado?

Minha recomendação é não. Mas Udi Dahan tem uma opinião diferente que você deve revisar; é que o CQRS só faz sentido se seus agregados forem sagas - o Udi usou a saga no local em que o gerente de processos se tornou a ortografia dominante.

os gerentes de processo devem recuperar agregados?

Na verdade não? Os gerentes de processo estão preocupados principalmente com a orquestração, não com o estado do domínio. Uma instância de um processo terá "estado", na forma de uma história de todos os eventos que eles observaram - a coisa correta a ser feita em resposta ao evento Z depende se vimos ou não os eventos X e Y Portanto, pode ser necessário armazenar e carregar uma representação desse estado (que pode ser algo simples ou pode ser o histórico de eventos observados).

(Eu digo "não realmente" porque agregado é definido de maneira vaga o suficiente para não ser totalmente errado afirmar que a lista de eventos observados é um "agregado". As diferenças são mais semânticas que a implementação - carregamos o estado do processo e depois decidimos quais mensagens enviar para as partes do sistema responsável pelo estado do domínio . Há um pouco de aceno manual aqui.)

Portanto, o PM não precisa usar um tipo de gerenciamento de estado em detrimento de outro, porque é o único responsável por fazer as coisas ao vivo e nunca durante repetições?

Não é bem assim - a administração do estado não é um fazedor, é um detentor de rastreadores. Nas circunstâncias em que o gerente do processo não deve emitir nenhum sinal, você fornece conexões inertes ao mundo. Em outras palavras, dispatch(command)é um no-op.


1
Você diz: Você pode reconstruir o gerenciador de processos a partir do histórico de eventos sempre que precisar ... Mas, para reconstruí-lo, preciso salvar eventos para ele. Ou devo reconstruí-lo a partir dos eventos nos agregados? A parte com a qual estou lutando é: com agregados, os eventos têm o ID agregado, e é fácil reconstruir encontrando todos os eventos com esse ID agregado. Mas como eu faria isso pelo gerente de processos? Devo fazer isso para o gerente de processos? Ou o gerente de processos deve procurar os agregados quando precisar decidir algo com base em um evento que entrou?
Ivan Pintar 06/10

O que estava faltando era a noção de causalidade e correlação no fornecimento de eventos. Depois de analisar isso, sua resposta para a quarta pergunta finalmente fez sentido.
Ivan Pintar 8/10

1
Gostaria de responder ao primeiro comentário de @IvanPintar; os gerentes de processo devem recuperar agregados? Eles devem criar seus próprios com base nos eventos que processa? Nesse caso, os manipuladores de eventos precisariam ser livres de efeitos colaterais, certo?
Jeff

@ Jeff Em um exemplo que fiz, o gerente de processos tinha seu próprio armazenamento, atualizado a cada evento processado, uma espécie de modelo de leitura. Era simples de fazer e era fácil rastrear o que já processava. Em outro exemplo, o gerenciador de processos criou e armazenou seus próprios eventos, criados a partir dos eventos agregados. Semelhante ao anterior, mas o estado foi originado por eventos. Dependendo da complexidade do estado que o gerente de processos mantém, pode ser mais fácil executar um ou outro. Achei a primeira abordagem mais simples.
Ivan Pintar

Interessante, então depende mais ou menos do desenvolvedor, desde que o gerente de processos responda a eventos e envie comandos no final?
Jeff

2

O que você está procurando tem um padrão chamado "Saga", que é essencialmente um gerenciador de processos.

Os Saga também são perfeitos para processos de execução longa, porque podem manter o estado entre os comandos correlacionados.

Aqui está um ótimo artigo sobre Sagas

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.