
Kürzlich haben meine Freunde und ich im Podcast von Zinc Prod das CQRS / ES-Muster und einige Funktionen seiner Implementierung in Elixir besprochen. Weil Ich benutze Laravel in meiner Arbeit, es war eine Sünde, nicht ins Internet einzutauchen und nicht herauszufinden, wie man diesen Ansatz im Ökosystem dieses Frameworks schlürft.
Ich lade alle unter dem Schnitt ein, ich habe versucht, das Thema so abstrakt wie möglich zu beschreiben.
Einige Definitionen
CQRS (Command Query Responsibility Segregation) - Zuordnung von Lese- und Schreibvorgängen zu separaten Entitäten. Zum Beispiel schreiben wir an den Master, lesen aus dem Replikat. CQRS. Fakten und Missverständnisse - Hilft bei der gründlichen Kenntnis von Zen CQRS.
ES (Event Sourcing) - Speicherung aller Statusänderungen einer Entität oder einer Gruppe von Entitäten.
CQRS / ES ist ein Architekturansatz, bei dem wir alle Ereignisse einer Statusänderung einer Entität in der Ereignistabelle speichern und diesem ein Aggregat und einen Projektor hinzufügen.
Aggregat - speichert die für das Treffen von Geschäftslogikentscheidungen (um das Schreiben zu beschleunigen) erforderlichen Eigenschaften im Speicher, trifft Entscheidungen (Geschäftslogik) und veröffentlicht Ereignisse.
Projektor - hört Ereignisse ab und schreibt in separate Tabellen oder Datenbanken (zum schnelleren Lesen).

In der Schlacht
Laravel Event Projektor - CQRS / ES Bibliothek für Laravel
Die Larabank ist ein Repository mit einem CQRS / ES-Ansatz. Wir werden es vor Gericht stellen.
In der Bibliothekskonfiguration erfahren Sie, wo Sie suchen und was es ist. Wir schauen uns die Datei event-projector.php an . Von den zur Beschreibung der Arbeit notwendigen:
projectors
- Projektoren registrieren;reactors
- Registerreaktoren. Reaktor - In dieser Bibliothek werden der Ereignisverarbeitung Nebenwirkungen hinzugefügt. Wenn Sie beispielsweise in diesem Repository versuchen, das Auszahlungslimit dreimal zu überschreiten, wird das MoreMoneyNeeded- Ereignis geschrieben und dem Benutzer eine Nachricht über seine finanziellen Schwierigkeiten gesendet.replay_chunk_size
- Größe des Wiederholungsblocks. Eine der Funktionen von ES ist die Möglichkeit, den Verlauf von Ereignissen wiederherzustellen. Mit dieser Einstellung wurde der Laravel-Ereignisprojektor für einen Speicherverlust während eines solchen Vorgangs vorbereitet.
Achten Sie auf Migration. Zusätzlich zu Standard-Laravel-Tischen haben wir
stored_events
- Die Haupt-ES-Tabelle mit mehreren Spalten unstrukturierter Daten für stored_events
Wir speichern Ereignistypen in einer Zeile. Wichtige Spalte aggregate_uuid
- speichert die uuid des Aggregats, um alle damit verbundenen Ereignisse zu erhalten;accounts
- Die Tabelle des Projektors der Benutzerkonten ist für die schnelle Rückgabe der aktuellen Daten zum Saldostatus erforderlich.transaction_counts
- Eine Tabelle des Projektors mit der Anzahl der Benutzertransaktionen, die für die schnelle Rückgabe der Anzahl der abgeschlossenen Transaktionen erforderlich ist.
Und jetzt schlage ich vor, mit der Bitte, ein neues Konto zu erstellen, auf die Straße zu gehen.
Kontoerstellung
Das Standard- resource
beschreibt den AccountsController . Wir interessieren uns für die store
Methode
public function store(Request $request) { $newUuid = Str::uuid();
AccountAggregateRoot erbt die Bibliothek AggregateRoot . Schauen wir uns die Methoden an, die der Controller aufgerufen hat.
Die persist
Methode ruft die storeMany
Methode storeMany
das in der event-projector.php- Konfiguration angegebene Modell als stored_event_model
in unserem Fall StoredEvent auf
public static function storeMany(array $events, string $uuid = null): void { collect($events) ->map(function (ShouldBeStored $domainEvent) use ($uuid) { $storedEvent = static::createForEvent($domainEvent, $uuid); return [$domainEvent, $storedEvent]; }) ->eachSpread(function (ShouldBeStored $event, StoredEvent $storedEvent) {
* QueuedProjector
Projektoren AccountProjector und TransactionCountProjector implementieren Projector
daher reagieren sie synchron mit ihrer Aufzeichnung auf Ereignisse.
Ok, ein Konto wurde erstellt. Ich schlage vor zu überlegen, wie der Kunde es lesen wird.
Rechnungsanzeige
Wenn der Projektor von Konten die QueuedProjector- Schnittstelle implementiert, sieht der Benutzer nichts, bis das Ereignis der Reihe nach verarbeitet wird.
Schließlich werden wir untersuchen, wie das Auffüllen und Abheben von Geld vom Konto funktioniert.
Aufladen und Abheben
Schauen Sie sich noch einmal den AccountsController an :
Betrachten Sie AccountAggregateRoot
beim Auffüllen des Kontos:
public function addMoney(int $amount) { $this->recordThat(new MoneyAdded($amount)); return $this; }
* AggregateRoot
beim Abheben von Geldern:
public function subtractMoney(int $amount) { if (!$this->hasSufficientFundsToSubtractAmount($amount)) {

Fazit
Ich habe versucht, den Prozess des „Onboarding“ in CQRS / ES auf Laravel so wasserfrei wie möglich zu beschreiben. Das Konzept ist sehr interessant, aber nicht ohne Funktionen. Beachten Sie vor der Implementierung Folgendes:
- eventuelle Konsistenz;
- Es ist wünschenswert, DDD in separaten Domänen zu verwenden. Sie sollten ein großes System nicht vollständig nach diesem Muster erstellen.
- Änderungen am Layout der Ereignistabelle können sehr schmerzhaft sein
- Verantwortungsbewusst lohnt es sich, sich der Wahl der Granularität von Ereignissen zu nähern. Je konkreter Ereignisse sind, desto mehr werden sie in der Tabelle aufgeführt und desto mehr Ressourcen werden benötigt, um mit ihnen zu arbeiten.
Ich werde mich freuen, Fehler zu bemerken.