Ich arbeite an einer kleinen Beispielanwendung, um die Konzepte von CQRS und Event-Sourcing zu erlernen. Ich habe ein Basket
Aggregat und ein Product
Aggregat, die unabhängig voneinander arbeiten sollten.
Hier ist ein Pseudocode zur Veranschaulichung der Implementierung
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; }
Befehle sind den Ereignissen ziemlich ähnlich und verwenden den imperativen Namen und nicht die Vergangenheitsform.
Im Moment funktionieren diese unabhängig voneinander einwandfrei. Ich gebe einen Befehl aus AddItem
und es wird ein ItemAdded
Ereignis auf dem Basket
Aggregat erstellt, das das tut, was es mit dem Status des 'Basket' zu tun hat. In ähnlicher Weise funktionieren der Befehl und die Ereignisse für das Produkt einwandfrei.
Ich möchte dies jetzt zu einem Prozess kombinieren, der ungefähr so ablaufen würde (in Bezug auf Befehle und Ereignisse, die passieren):
Der Prozessmanager würde Folgendes tun:
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...
Die Fragen, auf die ich keine endgültigen Antworten finden konnte, sind:
- Muss ich den Prozessmanager beibehalten? Es scheint so, als ob ich es tue, aber ich bin mir nicht sicher
- In diesem Fall muss ich die Ereignisse für den Prozessmanager speichern. Die Ereignisse, die abgehört werden, sind jedoch an die Aggregate gebunden. Füge ich diesen die Prozess-ID hinzu? Habe ich separate Ereignisse nur für den Prozessmanager? Wie man das macht und so trocken wie möglich hält
- Woher weiß ich, für welchen Warenkorb die
ProductReserved
Veranstaltungen sind? Ist es in Ordnung, eineBasketId
zu haben, oder sind das undichte Informationen? - Wie halte ich eine Beziehung zwischen Ereignissen, woher weiß ich,
ItemAdded
welchesProductReserved
Ereignis welches hervorgebracht hat ? Gebe ich einEventId
? Das scheint seltsam ... - Sollte ich das
Basket
als Prozessmanager anstelle eines einfachen Aggregats implementieren ?
Nach einigen weiteren Nachforschungen bin ich zu folgendem gekommen: Eine Saga ist etwas, das seine eigenen Ereignisse beibehält und Ereignisse von außen abhört. Grundsätzlich ist es ein Aggregat, das auch auf Ereignisse außerhalb seiner eigenen kleinen Welt reagieren kann.
Ein Prozessmanager arbeitet mit den Ereignissen von außen und sendet Befehle aus. Der Verlauf kann anhand der Ereignisse auf den Aggregaten wiederhergestellt werden, die einen gemeinsamen Bezeichner wie eine Korrelations-ID haben.
quelle
Antworten:
Lesen Sie, was Rinat Abdullin über die Entwicklung von Geschäftsprozessen geschrieben hat . Beachten Sie insbesondere seine Empfehlung für die Entwicklung eines Geschäftsprozesses in einer sich schnell ändernden Umgebung - ein Prozessmanager ist "nur" ein automatisierter Ersatz für einen Menschen, der auf einen Bildschirm starrt.
Mein eigenes mentales Modell eines Prozessmanagers ist, dass es sich um eine ereignisgesteuerte Projektion handelt, die Sie nach einer Liste ausstehender Befehle abfragen können.
Es ist ein Lesemodell. Sie können den Prozessmanager jedes Mal, wenn Sie ihn benötigen, aus dem Verlauf der Ereignisse neu erstellen. oder Sie können es wie einen Schnappschuss behandeln, den Sie aktualisieren.
Nein - der Prozessmanager ist ein Manager . Es macht nichts Nützliches für sich allein; Stattdessen werden die Aggregate angewiesen, ihre Arbeit zu erledigen (dh Änderungen am Buch der Aufzeichnungen vorzunehmen).
Sicher. Hinweis: In den meisten "echten" Einkaufsdomains würden Sie nicht darauf bestehen, Inventar zu reservieren, bevor Sie eine Bestellung bearbeiten. es fügt dem Geschäft unnötige Konkurrenz hinzu. Es ist wahrscheinlicher, dass Ihr Unternehmen die Bestellung annehmen möchte, und sich dann in dem seltenen Fall entschuldigen möchte, dass die Bestellung nicht in der erforderlichen Zeit ausgeführt werden kann.
Nachrichten haben Metadaten - insbesondere können Sie einen causationIdentifier (damit Sie identifizieren können, welche Befehle welche Ereignisse erzeugt haben) und einen correlationIdentifier einschließen , um die Konversation im Allgemeinen zu verfolgen.
Beispielsweise schreibt der Prozessmanager eine eigene ID als correlationId in den Befehl. Die von einer Kopie erzeugten Ereignisse enthalten die Korrelations-ID des Befehls, und Ihr Prozessmanager abonniert alle Ereignisse mit einer eigenen Korrelations-ID.
Meine Empfehlung lautet nein. Aber Udi Dahan hat eine andere Meinung, die Sie überprüfen sollten; Dies bedeutet, dass CQRS nur Sinn macht, wenn Ihre Aggregate Sagen sind. Udi verwendete Saga an der Stelle, an der der Prozessmanager die vorherrschende Schreibweise geworden ist.
Nicht wirklich? Prozessmanager befassen sich hauptsächlich mit der Orchestrierung und nicht mit dem Domänenstatus. Eine Instanz eines Prozesses hat einen "Zustand" in Form eines Verlaufs aller Ereignisse, die sie beobachtet haben. Die richtige Vorgehensweise bei Ereignis Z hängt davon ab, ob wir Ereignisse X und Y gesehen haben oder nicht Sie müssen möglicherweise in der Lage sein, eine Darstellung dieses Zustands zu speichern und zu laden.
(Ich sage „nicht wirklich“ , weil Aggregat vage genug definiert ist , dass es nicht ganz falsch ist , dass die Liste der beobachteten Ereignisse Anspruch ist ein „Aggregat“ Die Unterschiede mehr semantische sind als Implementierung -. Wir laden Prozesszustand und dann entscheiden , welche Nachrichten zu sende es an die Teile des Systems, die für den Domain-Status verantwortlich sind.
Nicht ganz - das Staatsmanagement ist kein Macher, es ist ein Wächter-Verfolger. In Situationen, in denen der Prozessmanager keine Signale senden sollte, geben Sie ihm träge Verbindungen zur Welt. Mit anderen Worten,
dispatch(command)
ist ein No-Op.quelle
Was Sie suchen, hat ein Muster namens "Saga", das im Wesentlichen ein Prozessmanager ist.
Saga-Befehle eignen sich auch für Prozesse mit langer Laufzeit, da sie den Status zwischen korrelierten Befehlen aufrechterhalten können.
Hier ist ein großartiger Artikel über Sagas
quelle