You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: commander/README.md
+28-90
Original file line number
Diff line number
Diff line change
@@ -31,108 +31,46 @@ In plain words
31
31
32
32
Managing transactions across different services in a distributed system, such as an e-commerce platform with separate `Payment` and `Shipping` microservices, requires careful coordination to avoid issues. When a user places an order but one service (e.g., `Payment`) is unavailable while the other (e.g., `Shipping`) is ready, we need a robust solution to handle this discrepancy.
33
33
34
-
A strategy to address this involves using a `Commander` component that orchestrates the process. Initially, the order is processed by the available service (`Shipping` in this case). The commander then attempts to synchronize the order with the currently unavailable service (`Payment`) by storing the order details in a database or queueing it for future processing. This queueing system must also account for possible failures in adding requests to the queue.
34
+
A strategy to address this involves using a `Commander` component that orchestrates the process. Initially, the order is processed by the available service (`Shipping` in this case). The `Commander` then attempts to synchronize the order with the currently unavailable service (`Payment`) by storing the order details in a database or queueing it for future processing. This queueing system must also account for possible failures in adding requests to the queue.
35
35
36
36
The `Commander` repeatedly tries to process the queued orders to ensure both services eventually reflect the same transaction data. This process involves ensuring idempotence, meaning that even if the same order synchronization request is made multiple times, it will only be executed once, preventing duplicate transactions. The goal is to achieve eventual consistency across services, where all systems are synchronized over time despite initial failures or delays.
37
37
38
-
To get a grasp of how this works in practice, let's see `AppShippingFailCases` class and explain afterward how it works.
38
+
Here's a simplified example of how the `Commander` class is used in the `AppAllCases` class:
var ms =newMessagingService(newMessagingDatabase());
78
-
var eh =newEmployeeHandle(newEmployeeDatabase());
79
-
var qdb =newQueueDatabase();
80
-
var c =newCommander(eh, ps, ss, ms, qdb, retryParams, timeLimits);
81
-
var user =newUser("Jim", "ABCD");
82
-
var order =newOrder(user, "book", 10f);
83
-
c.placeOrder(order);
84
-
}
85
-
86
-
voidshippingSuccessCase() {
87
-
//goes to payment after 2 retries maybe - rest is successful for now
88
-
var ps =newPaymentService(newPaymentDatabase(), newDatabaseUnavailableException());
89
-
var ss =newShippingService(newShippingDatabase(), newDatabaseUnavailableException(),
90
-
newDatabaseUnavailableException());
91
-
var ms =newMessagingService(newMessagingDatabase(), newDatabaseUnavailableException());
92
-
var eh =newEmployeeHandle(newEmployeeDatabase());
93
-
var qdb =newQueueDatabase();
94
-
var c =newCommander(eh, ps, ss, ms, qdb, retryParams, timeLimits);
95
-
var user =newUser("Jim", "ABCD");
96
-
var order =newOrder(user, "book", 10f);
97
-
c.placeOrder(order);
98
-
}
99
-
100
-
publicstaticvoidmain(String[] args) {
101
-
var asfc =newAppShippingFailCases();
102
-
asfc.shippingSuccessCase();
103
-
}
41
+
publicclassAppAllCases {
42
+
// ... other methods ...
43
+
44
+
// Shipping Database Fail Cases
45
+
voiditemUnavailableCase() {
46
+
var ps =newPaymentService(newPaymentDatabase());
47
+
var ss =newShippingService(newShippingDatabase(), newItemUnavailableException());
48
+
var ms =newMessagingService(newMessagingDatabase());
49
+
var eh =newEmployeeHandle(newEmployeeDatabase());
50
+
var qdb =newQueueDatabase();
51
+
// Create a Commander instance
52
+
var c =newCommander(eh, ps, ss, ms, qdb, retryParams, timeLimits);
53
+
var user =newUser("Jim", "ABCD");
54
+
var order =newOrder(user, "book", 10f);
55
+
// Use the Commander instance to place an order
56
+
c.placeOrder(order);
57
+
}
58
+
59
+
// ... other methods ...
104
60
}
105
61
```
106
62
107
-
The `AppShippingFailCases` class is designed to simulate different scenarios where the Shipping service is available or unavailable. It uses the Commander pattern to handle distributed transactions across multiple services.
63
+
In the `itemUnavailableCase` method, a `Commander` instance is created with the respective services and their databases. Then, a `User` and an `Order` are created, and the `placeOrder` method of the `Commander` instance is called with the order. This triggers the process of placing the order and handling any failures according to the Commander pattern.
108
64
109
-
Here's a breakdown of the methods in the `AppShippingFailCases` class:
65
+
The `Commander` class encapsulates the logic for handling the order placement and any potential failures. This separation of concerns makes the code easier to understand and maintain, and it allows for the reuse of the `Commander` class in different parts of the application. In a real-world application, the `Commander` class would be more complex and would include additional logic for handling different types of failures, retrying failed operations, and coordinating transactions across multiple services.
110
66
111
-
1.`itemUnavailableCase`: This method simulates a scenario where the item to be shipped is unavailable. It creates instances of the `Commander` class with the `ShippingService` throwing an `ItemUnavailableException`. An order is placed and the system tries to handle this failure.
112
-
113
-
2.`shippingNotPossibleCase`: This method simulates a scenario where shipping is not possible. It creates instances of the `Commander` class with the `ShippingService` throwing a `ShippingNotPossibleException`. An order is placed and the system tries to handle this failure.
114
-
115
-
3.`shippingDatabaseUnavailableCase`: This method simulates a scenario where the `ShippingService` and `ShippingDatabase` are unavailable. It creates instances of the `Commander` class with the `ShippingService` throwing multiple `DatabaseUnavailableException`. An order is placed and the system tries to handle this failure.
116
-
117
-
4.`shippingSuccessCase`: This method simulates a successful scenario where all services are available except for some temporary unavailability of the `PaymentService`, `ShippingService`, and `MessagingService`. An order is placed and the system handles this situation.
118
-
119
-
In each of these methods, a `Commander` instance is created with the respective services and their databases. Then, a `User` and an `Order` are created, and the `placeOrder` method of the `Commander` instance is called with the order. This triggers the process of placing the order and handling any failures according to the Commander pattern.
120
-
121
-
In the `main` method, the `shippingSuccessCase` method is called to simulate a successful scenario.
122
-
123
-
Finally, let's execute the `main` method see the program output.
67
+
Here is the output from executing the `itemUnavailableCase`:
124
68
125
69
```
126
-
18:01:07.738 [main] DEBUG com.iluwatar.commander.Commander -- Order I07V78ZOB8RZ: Error in connecting to shipping service, trying again..
127
-
18:01:10.536 [main] DEBUG com.iluwatar.commander.Commander -- Order I07V78ZOB8RZ: Error in connecting to shipping service, trying again..
128
-
18:01:15.401 [main] INFO com.iluwatar.commander.Commander -- Order I07V78ZOB8RZ: Shipping placed successfully, transaction id: RCM0PO9N9B6J
129
-
18:01:15.401 [main] INFO com.iluwatar.commander.Commander -- Order has been placed and will be shipped to you. Please wait while we make your payment...
130
-
18:01:15.407 [Thread-0] DEBUG com.iluwatar.commander.Commander -- Order I07V78ZOB8RZ: Error in connecting to payment service, trying again..
131
-
18:01:18.327 [Thread-0] INFO com.iluwatar.commander.Commander -- Order I07V78ZOB8RZ: Payment successful, transaction Id: UWS72C00JN9Q
132
-
18:01:18.328 [Thread-0] INFO com.iluwatar.commander.Commander -- Payment made successfully, thank you for shopping with us!!
133
-
18:01:18.332 [Thread-1] DEBUG com.iluwatar.commander.Commander -- Order I07V78ZOB8RZ: Error in connecting to messaging service (Payment Success msg), trying again..
134
-
18:01:20.693 [Thread-1] INFO com.iluwatar.commander.messagingservice.MessagingService -- Msg: Your order has been placed and paid for successfully! Thank you for shopping with us!
135
-
18:01:20.694 [Thread-1] INFO com.iluwatar.commander.Commander -- Order I07V78ZOB8RZ: Payment Success message sent, request Id: 72DOWH1D0WYS
70
+
09:10:13.894 [main] DEBUG com.iluwatar.commander.Commander -- Order YN3V8B7IL2PI: Error in creating shipping request..
71
+
09:10:13.896 [main] INFO com.iluwatar.commander.Commander -- This item is currently unavailable. We will inform you as soon as the item becomes available again.
72
+
09:10:13.896 [main] INFO com.iluwatar.commander.Commander -- Order YN3V8B7IL2PI: Item book unavailable, trying to add problem to employee handle..
73
+
09:10:13.897 [Thread-0] INFO com.iluwatar.commander.Commander -- Order YN3V8B7IL2PI: Added order to employee database
0 commit comments