2013-04-27 6 views
0

Je suis nouveau dans le CQRS et les modèles de cohérence éventuelle, alors pardonnez-moi si c'est une question stupide. Étant donné que je ne fais que commencer, j'ai une mémoire locale CommandBus et EventPublisher. Mes événements sont conservés dans une base de données RavenDB à des fins de relecture, mais les événements sont publiés et les gestionnaires sont appelés localement (pas en file d'attente externe via NServiceBus et al). EventPublisher publie des événements de manière asynchrone (par exemple, Task.Factory.StartNew).CQRS dépendances Event Event Cohérence

Parfois, mes événements ont des dépendances (par exemple, l'événement OrderReceived doit être traité dans ReadModel avant que l'événement OrderShipmentStatusUpdated puisse être correctement traité dans ReadModel).

Comment puis-je gérer ce genre de scénario? Utiliser Sagas? Comment utiliser Sagas dans un modèle simple en mémoire comme décrit ci-dessus? Est-il considéré comme acceptable de «différer» un événement (peut-être le marquer comme différé et simplement essayer de retraiter tous les événements différés «de temps en temps»)?

Quelles sont les stratégies pour y faire face?

Merci.

+0

avez-vous publié des événements de manière asynchrone? Si les événements sont publiés de manière synchrone, vous n'aurez aucun problème avec l'ordre des événements et vous ne devriez pas avoir de problème avec la cohérence éventuelle, car ils s'exécuteront dans le même thread que la commande. – Sarmaad

+0

Performance. Et j'aurais encore des problèmes à moins que je synchronise à travers toutes les demandes de Web et ai seulement 1 serveur, non? – Jeff

+0

@Jeff: Je pense que Sarmaad voulait dire que OrderReceived et OrderShipmentStatusUpdated devraient être traités de manière synchrone. – IlliakaillI

Répondre

3

Une file d'attente avec des tentatives la plupart du temps résout ces problèmes. Si votre gestionnaire/agrégat/dénormaliseur ne peut pas traiter un message, car les conditions préalables ne sont pas remplies - échouez difficilement. Ensuite, vous traiterez d'autres messages de la file jusqu'à ce que celui-ci redevienne visible. Si le message échoue plus de 3 fois, ignorez-le en erreur file d'attente pour une analyse plus approfondie.

Si c'est un flux de travail attendu et que vous devez attendre - créez Saga si vous ne modélisez pas avec DDD/Event Sourcing. Si la modélisation avec DDD/Event Sourcing - Aggregates couvre la plupart du temps cette fonctionnalité.

1

Il est préférable d'utiliser les données du magasin d'événements au lieu des données de Read Model pour le traitement de l'événement OrderShipmentStatusUpdated, cela résoudra les problèmes liés à la cohérence éventuelle. Le magasin d'événements est la seule source de vérité.

+0

Comment est-ce que je m'assure que les événements sont traités de manière synchrone quand seulement en utilisant une mémoire en même tpublisher? – Jeff

+0

Et dites-vous que mes gestionnaires d'événements de modèle de lecture (dénormalizers) devraient utiliser mon EventSource comme un moyen de mettre à jour le modèle lu? – Jeff

2

La question est de savoir pourquoi les événements arrivent dans le désordre?

Si c'est à cause de "forces techniques", vous pouvez regarder votre infrastructure pour y remédier, mais cela nécessiterait normalement une file d'attente de messages complète.

Si les messages/événements ne sont pas synchronisés en raison des "processus métier", vous pouvez alors consulter Sagas/ProcessManager. Jetez un oeil à l'approche de Greg Young d'utiliser le event store as queue. Pour en savoir plus sur le report d'événements: Vous pouvez envisager une approche simplifiée en modélisant la commande requise à l'aide de Granulats. Il va consommer des événements et notifier le côté lecture uniquement lorsque les conditions sont remplies. La vue ne projette que les événements qui ont été "validés" par l'agrégat. Vous avez l'avantage de rendre les concepts implicites explicites dans votre modèle. L'inconvénient est que vous aurez plus d'événements générés. (Oui, rien n'est gratuit)

Jetez un oeil à Rinat Abdullin’s approach à ce sujet. C'est un post vieux mais intéressant et peut-être se référer au podcast Being The Worst qui couvre également une partie de ceci.

2

Je suis d'accord avec ILICH.

Des événements se sont produits et le modèle de lecture doit simplement signaler cela. Le modèle de lecture ne doit pas être en mesure de valider les événements.

Il peut être plus facile d'avoir la logique d'expédition dans le modèle de domaine plutôt que de créer une nouvelle saga.

Une autre façon de «tricher» sur un projet plus petit consiste à utiliser l'événement comme déclencheur pour lire le journal des événements. Ainsi, lorsque votre modèle de lecture reçoit une notification d'événement, il doit charger tous les «nouveaux» événements du magasin d'événements. Cela garantit que rien n'est perdu pendant le transport et simplifie ce que vous utilisez pour le bus.Dans la phase de prototypage, il vous permet également de souffler vos modèles de lecture à volonté et de les faire reconstruire automatiquement.

Je garde une petite table de "l'historique des travaux" qui reflète l'événement le plus récent consommé pour traiter un modèle de lecture particulier. Si je veux changer le schéma du modèle lu, je supprime simplement l'enregistrement approprié.

1

Sur les problèmes de synchronisation/événement async édition:

en enveloppant la donnée DomainEvents avec un objet EventCommit ayant un commits id persistait dans le magasin d'événements, nous pourrions traiter de manière asynchrone les objets EventCommit, tandis que le DomainEvents au sein les EventCommit ont été publiés de manière synchrone. L'emballage se produit dans notre UnitOfWork qui suit nos agrégats en mémoire lorsque les modifications apportées à un agrégat donné sont demandées. Du côté lecture, l'identifiant de validation peut être utilisé pour vérifier l'ordre correct directement dans le processus de dépôt avant d'envoyer les événements aux gestionnaires.