Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:28:30 +08:00
commit 171acedaa4
220 changed files with 85967 additions and 0 deletions

View File

@@ -0,0 +1,153 @@
# Choreography-Based Saga Implementation
## Architecture Overview
In choreography-based sagas, each service produces and listens to events. Services know what to do when they receive an event. **No central coordinator** manages the flow.
```
Service A → Event → Service B → Event → Service C
↓ ↓ ↓
Event Event Event
↓ ↓ ↓
Compensation Compensation Compensation
```
## Event Flow
### Success Path
1. **Order Service** creates order → publishes `OrderCreated` event
2. **Payment Service** listens → processes payment → publishes `PaymentProcessed` event
3. **Inventory Service** listens → reserves inventory → publishes `InventoryReserved` event
4. **Shipment Service** listens → prepares shipment → publishes `ShipmentPrepared` event
### Failure Path (When Payment Fails)
1. **Payment Service** publishes `PaymentFailed` event
2. **Order Service** listens → cancels order → publishes `OrderCancelled` event
3. All other services respond to cancellation with cleanup
## Event Publisher
```java
@Component
public class OrderEventPublisher {
private final StreamBridge streamBridge;
public OrderEventPublisher(StreamBridge streamBridge) {
this.streamBridge = streamBridge;
}
public void publishOrderCreatedEvent(String orderId, BigDecimal amount, String itemId) {
OrderCreatedEvent event = new OrderCreatedEvent(orderId, amount, itemId);
streamBridge.send("orderCreated-out-0",
MessageBuilder
.withPayload(event)
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
.build());
}
}
```
## Event Listener
```java
@Component
public class PaymentEventListener {
@Bean
public Consumer<OrderCreatedEvent> handleOrderCreatedEvent() {
return event -> processPayment(event.getOrderId());
}
private void processPayment(String orderId) {
// Payment processing logic
}
}
```
## Event Classes
```java
public record OrderCreatedEvent(
String orderId,
BigDecimal amount,
String itemId
) {}
public record PaymentProcessedEvent(
String paymentId,
String orderId,
String itemId
) {}
public record PaymentFailedEvent(
String paymentId,
String orderId,
String itemId,
String reason
) {}
```
## Spring Cloud Stream Configuration
```yaml
spring:
cloud:
stream:
bindings:
orderCreated-out-0:
destination: order-events
paymentProcessed-out-0:
destination: payment-events
paymentFailed-out-0:
destination: payment-events
kafka:
binder:
brokers: localhost:9092
```
## Maven Dependencies
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-kafka</artifactId>
</dependency>
```
## Gradle Dependencies
```groovy
implementation 'org.springframework.cloud:spring-cloud-stream'
implementation 'org.springframework.cloud:spring-cloud-stream-binder-kafka'
```
## Advantages and Disadvantages
### Advantages
- **Simple** for small number of services
- **Loose coupling** between services
- **No single point of failure**
- Each service is independently deployable
### Disadvantages
- **Difficult to track workflow state** - distributed across services
- **Hard to troubleshoot** - following event flow is complex
- **Complexity grows** with number of services
- **Distributed source of truth** - saga state not centralized
## When to Use Choreography
Use choreography-based sagas when:
- Microservices are few in number (< 5 services per saga)
- Loose coupling is critical
- Team is experienced with event-driven architecture
- System can handle eventual consistency
- Workflow doesn't need centralized monitoring