feat: add Event-Carried State Transfer pattern (#2434) - #3602
Conversation
PR SummaryIntroduces the Event-Carried State Transfer (ECST) pattern as a new module Changes
autogenerated by presubmit.ai |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3602 +/- ##
============================================
+ Coverage 83.79% 83.87% +0.08%
- Complexity 4277 4320 +43
============================================
Files 1121 1130 +9
Lines 15144 15310 +166
Branches 723 729 +6
============================================
+ Hits 12690 12842 +152
- Misses 2159 2167 +8
- Partials 295 301 +6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
cabcc02 to
c92197c
Compare
|
Coverage follow-up: added |
There was a problem hiding this comment.
🚨 Pull request needs attention.
Review Summary
Files Processed (20)
- event-carried-state-transfer/README.md (1 hunk)
- event-carried-state-transfer/etc/event-carried-state-transfer.urm.puml (1 hunk)
- event-carried-state-transfer/pom.xml (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/App.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerReplica.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerService.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerState.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerUpdatedEvent.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/EventBus.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/EventListener.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/Order.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/OrderRejectedException.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/OrderService.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/AppTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/CustomerReplicaTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/CustomerServiceTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/CustomerStateTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/EventBusTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/OrderServiceTest.java (1 hunk)
- pom.xml (1 hunk)
Actionable Comments (5)
-
event-carried-state-transfer/pom.xml [1-70]
best_practice: "Add JUnit Jupiter API dependency"
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/App.java [60-60]
best_practice: "Logger name mismatch with Lombok"
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerService.java [1-145]
best_practice: "Logger name mismatch with Lombok"
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/OrderService.java [49-51]
best_practice: "Logger name mismatch with Lombok"
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/EventBus.java [56-56]
best_practice: "Logger name mismatch with Lombok"
Skipped Comments (1)
-
event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/EventBusTest.java [43-43]
readability: "Test listener compatibility with EventListener"
There was a problem hiding this comment.
🚨 Pull request needs attention.
Review Summary
Commits Considered (3)
- 00c006f: docs: embed the rendered class diagram in the event-carried state transfer README
Render etc/event-carried-state-transfer.urm.puml to PNG and embed it in the detailed explanation section, matching the other modules, instead of the inline mermaid block. The producer and consumer snippets now show the plain long sequence counters the code uses.
- 5bd0fd4: feat: demonstrate a credit limit change flowing through the replica
The demo never exercised changeCreditLimit, so the claim that the replica is
enough to enforce business rules was only shown as a rejection. Add a fifth
step: the customer service comes back online, raises the credit limit, and the
order rejected in step 4 is accepted from the replicated state alone.
Add restart() to CustomerService so the outage can end, make CustomerReplica
use a LinkedHashMap like CustomerService for deterministic log order, cover the
new behaviour in CustomerServiceTest and OrderServiceTest, and refresh the
README demo section, its program output, and the PlantUML diagram.
-
14c9e5d: fix: align event bus contract and class diagram with the code
-
document that EventBus dispatches by exact runtime class, so a listener
subscribed to a supertype never receives subclass events -
reject null events in EventBus.publish with Objects.requireNonNull and cover
it with a test -
replace the AtomicLong sequence counters in CustomerService and OrderService
with plain long fields and note that these classes are not thread-safe -
drop the implements-relationship between CustomerReplica and EventListener in
the PlantUML diagram; OrderService merely adapts the replica -
replace the raw .puml link in the README with an inline mermaid class diagram
Files Processed (11)
- event-carried-state-transfer/README.md (1 hunk)
- event-carried-state-transfer/etc/event-carried-state-transfer.urm.png (0 hunks)
- event-carried-state-transfer/etc/event-carried-state-transfer.urm.puml (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/App.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerReplica.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerService.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/EventBus.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/OrderService.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/CustomerServiceTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/EventBusTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/OrderServiceTest.java (1 hunk)
Actionable Comments (5)
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/App.java [62-62]
bug: "Logging: inconsistent logger name in App."
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/EventBus.java [59-59]
bug: "Logging: inconsistent logger name in EventBus."
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerService.java [73-73]
bug: "Logging: inconsistent logger name in CustomerService."
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerReplica.java [56-61]
bug: "Logging: inconsistent logger name in CustomerReplica."
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/OrderService.java [79-86]
bug: "Logging: inconsistent logger name in OrderService."
Skipped Comments (0)
00c006f to
ab69096
Compare
publish rejects null, exact-class dispatch is documented, the sequence counters are plain longs, and the demo shows a credit limit change flowing through the replica. The class diagram is a rendered PNG.
ab69096 to
1cb094e
Compare
There was a problem hiding this comment.
🚨 Pull request needs attention.
Review Summary
Commits Considered (2)
- 1cb094e: fix: align the event bus contract with the code and extend the demo
publish rejects null, exact-class dispatch is documented, the sequence counters are plain longs, and the demo shows a credit limit change flowing through the replica. The class diagram is a rendered PNG.
Files Processed (21)
- event-carried-state-transfer/README.md (1 hunk)
- event-carried-state-transfer/etc/event-carried-state-transfer.urm.png (0 hunks)
- event-carried-state-transfer/etc/event-carried-state-transfer.urm.puml (1 hunk)
- event-carried-state-transfer/pom.xml (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/App.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerReplica.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerService.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerState.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerUpdatedEvent.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/EventBus.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/EventListener.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/Order.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/OrderRejectedException.java (1 hunk)
- event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/OrderService.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/AppTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/CustomerReplicaTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/CustomerServiceTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/CustomerStateTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/EventBusTest.java (1 hunk)
- event-carried-state-transfer/src/test/java/com/iluwatar/eventcarriedstatetransfer/OrderServiceTest.java (1 hunk)
- pom.xml (1 hunk)
Actionable Comments (8)
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/App.java [62-66]
bug: "Logger name mismatch with Lombok in App"
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerService.java [73-75]
bug: "Logger name mismatch in CustomerService"
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerService.java [85-85]
bug: "Logger name mismatch in CustomerService"
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerService.java [97-97]
bug: "Logger name mismatch in CustomerService"
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/CustomerReplica.java [56-62]
bug: "Logger name mismatch in CustomerReplica"
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/OrderService.java [81-85]
bug: "Logger name mismatch in OrderService"
-
event-carried-state-transfer/src/main/java/com/iluwatar/eventcarriedstatetransfer/EventBus.java [59-59]
bug: "Logger name mismatch in EventBus"
-
event-carried-state-transfer/pom.xml [36-50]
maintainability: "JUnit 5 API dependency missing"
What does this PR do?
Adds the Event-Carried State Transfer (ECST) pattern as a new
event-carried-state-transfermodule.CustomerUpdatedEventcarries the full customer state and a version. The consumer keeps its own replica, serves its use cases from that replica alone, never calls the producer back, and keeps working when the producer is offline.CustomerState(versioned, immutable record) andCustomerUpdatedEvent(carries the complete state).EventBus/EventListener: tiny synchronous in-memory publish/subscribe keyed by event type.CustomerService(producer): owns the authoritative state, publishes a full-state event on every change, can be taken offline to demonstrate consumer autonomy.CustomerReplica(consumer-side store): version-guarded upsert that ignores stale or duplicate events.OrderService(consumer): places orders using only the replica (unknown customer and credit limit checks, shipping address snapshot); it has no reference toCustomerService.App: four logged steps: replica follows each change, order placed while the producer is offline, stale event ignored, business rule enforced from the replica.README.md: intent, real-world example, Fowler quote, sequence diagram, code walkthrough with real program output, applicability, trade-offs (eventual consistency, duplicated data, versioning), and an explicit paragraph on how ECST differs from event notification, event sourcing and pub-sub. PlantUML class diagram underetc/.Appconstructor.pom.xml../mvnw clean verify -pl event-carried-state-transferpasses locally on JDK 21 and inside aneclipse-temurin:21container; the packaged jar runs end to end.Fixes #2434