Skip to content

Commit 74f039f

Browse files
committed
docs: update event sourcing
1 parent 865d98c commit 74f039f

File tree

2 files changed

+91
-23
lines changed

2 files changed

+91
-23
lines changed

event-sourcing/README.md

Lines changed: 91 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,23 @@ Event Sourcing is a design pattern that advocates for the storage of state chang
2323

2424
## Explanation
2525

26-
Real world example
27-
28-
> The modern emailing system is an example of the fundamental process behind the event-queue design pattern. When an email is sent, the sender continues their daily tasks without the necessity of an immediate response from the receiver. Additionally, the receiver has the freedom to access and process the email at their leisure. Therefore, this process decouples the sender and receiver so that they are not required to engage with the queue at the same time.
26+
Real-world example
2927

28+
> Consider a banking application that tracks all transactions for user accounts. In this system, every deposit, withdrawal, and transfer is recorded as an individual event in an event log. Instead of simply updating the current account balance, each transaction is stored as a discrete event. This approach allows the bank to maintain a complete and immutable history of all account activities. If a discrepancy occurs, the bank can replay the sequence of events to reconstruct the account state at any point in time. This provides a robust audit trail, facilitates debugging, and supports features like transaction rollback and historical data analysis.
3029
3130
In plain words
3231

33-
> The buffer between sender and receiver improves maintainability and scalability of a system. Event queues are typically used to organise and carry out interprocess communication (IPC).
34-
35-
Wikipedia says
36-
37-
> Message queues (also known as event queues) implement an asynchronous communication pattern between two or more processes/threads whereby the sending and receiving party do not need to interact with the queue at the same time.
32+
> Event Sourcing records all state changes as a sequence of immutable events to ensure reliable state reconstruction and auditability.
3833
34+
[Microsoft's documentation](https://learn.microsoft.com/en-us/azure/architecture/patterns/event-sourcing) says
3935

40-
Key drawback
41-
42-
> As the event queue model decouples the sender-receiver relationship - this means that the event-queue design pattern is unsuitable for scenarios in which the sender requires a response. For example, this is a prominent feature within online multiplayer games, therefore, this approach require thorough consideration.
36+
> The Event Sourcing pattern defines an approach to handling operations on data that's driven by a sequence of events, each of which is recorded in an append-only store. Application code sends a series of events that imperatively describe each action that has occurred on the data to the event store, where they're persisted. Each event represents a set of changes to the data (such as AddedItemToOrder).
4337
4438
**Programmatic Example**
4539

46-
In the given code, we can see an example of the Event Sourcing pattern in the Event class. This class manages a queue of events and controls thread operations for asynchronous processing. Each event can be seen as a state change that affects the state of the system.
40+
In the programmatic example we transfer some money between bank accounts.
41+
42+
The `Event` class manages a queue of events and controls thread operations for asynchronous processing. Each event can be seen as a state change that affects the state of the system.
4743

4844
```java
4945
public class Event {
@@ -67,7 +63,7 @@ public class Event {
6763
}
6864
```
6965

70-
The triggerEvent method is where the events are created. Each time an event is triggered, it is created and added to the queue. This event contains the details of the state change.
66+
The `triggerEvent` method is where the events are created. Each time an event is triggered, it is created and added to the queue. This event contains the details of the state change.
7167

7268
```java
7369
public void triggerEvent(EventMessage eventMessage) {
@@ -83,7 +79,7 @@ public void triggerEvent(EventMessage eventMessage) {
8379
}
8480
```
8581

86-
The init and startThread methods ensure the thread is properly initialized and running. The stopService method is used to stop the thread when it's no longer needed. These methods manage the lifecycle of the thread used to process the events.
82+
The `init` and `startThread` methods ensure the thread is properly initialized and running. The `stopService` method is used to stop the thread when it's no longer needed. These methods manage the lifecycle of the thread used to process the events.
8783

8884
```java
8985
public synchronized void stopService() throws InterruptedException {
@@ -118,6 +114,84 @@ private synchronized void startThread() {
118114
}
119115
```
120116

117+
The example is driven by the `App` class and its `main` method.
118+
119+
```java
120+
@Slf4j
121+
public class App {
122+
123+
public static final int ACCOUNT_OF_DAENERYS = 1;
124+
125+
public static final int ACCOUNT_OF_JON = 2;
126+
127+
public static void main(String[] args) {
128+
129+
var eventProcessor = new DomainEventProcessor(new JsonFileJournal());
130+
131+
LOGGER.info("Running the system first time............");
132+
eventProcessor.reset();
133+
134+
LOGGER.info("Creating the accounts............");
135+
136+
eventProcessor.process(new AccountCreateEvent(
137+
0, new Date().getTime(), ACCOUNT_OF_DAENERYS, "Daenerys Targaryen"));
138+
139+
eventProcessor.process(new AccountCreateEvent(
140+
1, new Date().getTime(), ACCOUNT_OF_JON, "Jon Snow"));
141+
142+
LOGGER.info("Do some money operations............");
143+
144+
eventProcessor.process(new MoneyDepositEvent(
145+
2, new Date().getTime(), ACCOUNT_OF_DAENERYS, new BigDecimal("100000")));
146+
147+
eventProcessor.process(new MoneyDepositEvent(
148+
3, new Date().getTime(), ACCOUNT_OF_JON, new BigDecimal("100")));
149+
150+
eventProcessor.process(new MoneyTransferEvent(
151+
4, new Date().getTime(), new BigDecimal("10000"), ACCOUNT_OF_DAENERYS,
152+
ACCOUNT_OF_JON));
153+
154+
LOGGER.info("...............State:............");
155+
LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS).toString());
156+
LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_JON).toString());
157+
158+
LOGGER.info("At that point system had a shut down, state in memory is cleared............");
159+
AccountAggregate.resetState();
160+
161+
LOGGER.info("Recover the system by the events in journal file............");
162+
163+
eventProcessor = new DomainEventProcessor(new JsonFileJournal());
164+
eventProcessor.recover();
165+
166+
LOGGER.info("...............Recovered State:............");
167+
LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS).toString());
168+
LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_JON).toString());
169+
}
170+
}
171+
```
172+
173+
Running the example produces the following console output.
174+
175+
```
176+
22:40:47.982 [main] INFO com.iluwatar.event.sourcing.app.App -- Running the system first time............
177+
22:40:47.984 [main] INFO com.iluwatar.event.sourcing.app.App -- Creating the accounts............
178+
22:40:47.985 [main] INFO com.iluwatar.event.sourcing.domain.Account -- Some external api for only realtime execution could be called here.
179+
22:40:48.089 [main] INFO com.iluwatar.event.sourcing.domain.Account -- Some external api for only realtime execution could be called here.
180+
22:40:48.090 [main] INFO com.iluwatar.event.sourcing.app.App -- Do some money operations............
181+
22:40:48.090 [main] INFO com.iluwatar.event.sourcing.domain.Account -- Some external api for only realtime execution could be called here.
182+
22:40:48.095 [main] INFO com.iluwatar.event.sourcing.domain.Account -- Some external api for only realtime execution could be called here.
183+
22:40:48.099 [main] INFO com.iluwatar.event.sourcing.domain.Account -- Some external api for only realtime execution could be called here.
184+
22:40:48.099 [main] INFO com.iluwatar.event.sourcing.domain.Account -- Some external api for only realtime execution could be called here.
185+
22:40:48.101 [main] INFO com.iluwatar.event.sourcing.app.App -- ...............State:............
186+
22:40:48.104 [main] INFO com.iluwatar.event.sourcing.app.App -- Account{accountNo=1, owner='Daenerys Targaryen', money=90000}
187+
22:40:48.104 [main] INFO com.iluwatar.event.sourcing.app.App -- Account{accountNo=2, owner='Jon Snow', money=10100}
188+
22:40:48.104 [main] INFO com.iluwatar.event.sourcing.app.App -- At that point system had a shut down, state in memory is cleared............
189+
22:40:48.104 [main] INFO com.iluwatar.event.sourcing.app.App -- Recover the system by the events in journal file............
190+
22:40:48.124 [main] INFO com.iluwatar.event.sourcing.app.App -- ...............Recovered State:............
191+
22:40:48.124 [main] INFO com.iluwatar.event.sourcing.app.App -- Account{accountNo=1, owner='Daenerys Targaryen', money=90000}
192+
22:40:48.124 [main] INFO com.iluwatar.event.sourcing.app.App -- Account{accountNo=2, owner='Jon Snow', money=10100}
193+
```
194+
121195
In this example, the state of the system can be recreated at any point by replaying the events in the queue. This is a key feature of the Event Sourcing pattern.
122196

123197
## Class diagram
@@ -158,10 +232,8 @@ Benefits:
158232

159233
## Credits
160234

235+
* [Building Microservices: Designing Fine-Grained Systems](https://amzn.to/443WfiS)
161236
* [Implementing Domain-Driven Design](https://amzn.to/3JgvA8V)
162237
* [Patterns, Principles, and Practices of Domain-Driven Design](https://amzn.to/3VVhfWX)
163-
* [Building Microservices: Designing Fine-Grained Systems](https://amzn.to/443WfiS)
164-
* [Martin Fowler - Event Sourcing](https://martinfowler.com/eaaDev/EventSourcing.html)
165-
* [Event Sourcing in Microsoft's documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)
166-
* [Reference 3: Introducing Event Sourcing](https://msdn.microsoft.com/en-us/library/jj591559.aspx)
167-
* [Event Sourcing pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)
238+
* [Event Sourcing (Martin Fowler)](https://martinfowler.com/eaaDev/EventSourcing.html)
239+
* [Event Sourcing pattern (Microsoft)](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)

event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@
4949
* After the shut-down, system state is recovered by re-creating the past events from event
5050
* journals. Then state is printed so a user can view the last state is same with the state before a
5151
* system shut-down.
52-
*
53-
* <p>Created by Serdar Hamzaogullari on 06.08.2017.
5452
*/
5553
@Slf4j
5654
public class App {
@@ -112,6 +110,4 @@ public static void main(String[] args) {
112110
LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS).toString());
113111
LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_JON).toString());
114112
}
115-
116-
117113
}

0 commit comments

Comments
 (0)