μ΄ νλ‘μ νΈλ Temporalμ Saga Orchestratorλ‘, Spring Cloud Netflix Eurekaλ₯Ό μλΉμ€ λμ€μ»€λ²λ¦¬λ‘ μ¬μ©νμ¬ λ§μ΄ν¬λ‘μλΉμ€ κ° λΆμ° νΈλμμ μ κ΄λ¦¬νλ μμ μ λλ€.
- μν€ν μ²
- κΈ°μ μ€ν
- νλ‘μ νΈ κ΅¬μ‘°
- Saga νλ¦
- μ€ν λ°©λ²
- API ν μ€νΈ
- Eureka Dashboard
- Temporal Web UI
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ν΄λΌμ΄μΈνΈ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β order-service (8080) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β POST /api/orders β β
β β 1. μ¬κ³ νμΈ (Feign β inventory-service) [λκΈ°] β β
β β 2. μ£Όλ¬Έ μ μ₯ (PENDING) β β
β β 3. Workflow μμ (Temporal) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β Feign (λκΈ°) β Workflow μμ
βΌ βΌ
βββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββββββ
β inventory-service β β Temporal Server β
β (8083) β β (7233) β
βββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββββββ
β
β Task Queue ν΄λ§
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β saga-orchestrator (8082) β Orchestrator β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Temporal Worker β β
β β ββ OrderWorkflow (Saga λ‘μ§) β β
β β β ββ Step 1: reserveStock (inventory-service) β β
β β β ββ Step 2: processPayment (payment-service) β β
β β β ββ Step 3: completeOrder (order-service) β β
β β ββ 보μ νΈλμμ
β β
β β ββ releaseStock (μ¬κ³ ν΄μ ) β β
β β ββ refundPayment (κ²°μ νλΆ) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ
β inventory β β payment β β order β
β -service β β -service β β -service β
β (Activity) β β (Activity) β β (Activity) β
βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ
βββββββββββββββββββββββ
β Eureka Server β
β (8761) β
β μλΉμ€ λμ€μ»€λ²λ¦¬ β
βββββββββββββββββββββββ
β²
βββββββββββββββββββββββΌββββββββββββββββββββββ
β β β
order-service inventory-service payment-service
saga-orchestrator
| κ΅¬λΆ | κΈ°μ |
|---|---|
| Language | Java 21 |
| Framework | Spring Boot 3.3.x |
| Build Tool | Gradle 8.x |
| Service Discovery | Spring Cloud Netflix Eureka |
| λκΈ° νΈμΆ | OpenFeign |
| Saga Orchestration | Temporal |
| Database | H2 (in-memory), PostgreSQL (Temporal) |
| Container | Docker, Docker Compose |
saga-example/
βββ eureka-server/ # π Eureka Server (μλΉμ€ λμ€μ»€λ²λ¦¬)
β βββ src/main/java/com/example/eureka/
β βββ EurekaServerApplication.java
β
βββ saga-common/ # 곡μ λͺ¨λ (μΈν°νμ΄μ€, μμ)
β βββ src/main/java/com/example/saga/common/
β βββ workflow/
β β βββ OrderWorkflow.java
β β βββ OrderServiceActivities.java
β β βββ PaymentServiceActivities.java
β β βββ InventoryServiceActivities.java # π
β βββ constants/
β βββ SagaConstants.java
β
βββ inventory-service/ # π μ¬κ³ μλΉμ€ (λλ©μΈ)
β βββ src/main/java/com/example/inventory/
β βββ InventoryServiceApplication.java
β βββ domain/
β β βββ Inventory.java
β β βββ StockReservation.java
β βββ repository/
β βββ service/
β β βββ InventoryService.java
β β βββ InventoryServiceActivitiesImpl.java
β βββ controller/
β β βββ InventoryController.java
β βββ config/
β
βββ order-service/ # μ£Όλ¬Έ μλΉμ€ (+ Feign Client)
β βββ src/main/java/com/example/order/
β βββ OrderServiceApplication.java
β βββ client/ # π
β β βββ InventoryClient.java # Feign Client
β β βββ InventoryClientFallback.java
β βββ domain/
β βββ service/
β β βββ OrderService.java # μ¬κ³ νμΈ λ‘μ§ μΆκ°
β β βββ OrderServiceActivitiesImpl.java
β βββ ...
β
βββ payment-service/ # κ²°μ μλΉμ€
β βββ src/main/java/com/example/payment/
β βββ ...
β
βββ saga-orchestrator/ # Saga Orchestrator
β βββ src/main/java/com/example/orchestrator/
β βββ workflow/
β βββ OrderWorkflowImpl.java # μ¬κ³ Saga μΆκ°
β
βββ docker-compose.yml
βββ build.gradle
βββ settings.gradle
βββ README.md
saga-common (곡μ λΌμ΄λΈλ¬λ¦¬)
β
βββββββββββββββββΌββββββββββββββββ¬ββββββββββββββββ
β β β β
order-service inventory-service payment-service saga-orchestrator
(Workflow μμ) (Activity ꡬν) (Activity ꡬν) (Workflow ꡬν)
β
ββββ InventoryClient (Feign - λκΈ° νΈμΆ)
β
βΌ
inventory-service
β Eureka λ±λ‘ β
eureka-server (8761)
sequenceDiagram
participant Client
participant OrderService
participant InventoryService
participant Temporal
participant Orchestrator
participant PaymentService
Client->>OrderService: POST /api/orders<br/>{productId, quantity, amount: 50}
OrderService->>InventoryService: [Feign] μ¬κ³ νμΈ
InventoryService-->>OrderService: {available: true}
OrderService->>OrderService: μ£Όλ¬Έ μ μ₯ (PENDING)
OrderService->>Temporal: Start OrderWorkflow
OrderService-->>Client: 201 Created<br/>{id, status: PENDING}
Temporal->>Orchestrator: Task Queue ν΄λ§
Note over Orchestrator: [Step 1] μ¬κ³ μμ½
Orchestrator->>InventoryService: reserveStock()
InventoryService-->>Orchestrator: true (μμ½ μ±κ³΅)
Note over Orchestrator: [Step 2] κ²°μ μ²λ¦¬
Orchestrator->>PaymentService: processPayment()
PaymentService-->>Orchestrator: true (κ²°μ μ±κ³΅)
Note over Orchestrator: [Step 3] μ£Όλ¬Έ μλ£
Orchestrator->>OrderService: completeOrder()
Orchestrator->>InventoryService: confirmStock()
Note over Orchestrator: Saga μλ£ (μ±κ³΅)
sequenceDiagram
participant Client
participant OrderService
participant InventoryService
participant Temporal
participant Orchestrator
participant PaymentService
Client->>OrderService: POST /api/orders<br/>{productId, quantity, amount: 200}
OrderService->>InventoryService: [Feign] μ¬κ³ νμΈ
InventoryService-->>OrderService: {available: true}
OrderService->>OrderService: μ£Όλ¬Έ μ μ₯ (PENDING)
OrderService->>Temporal: Start OrderWorkflow
OrderService-->>Client: 201 Created
Temporal->>Orchestrator: Task Queue ν΄λ§
Note over Orchestrator: [Step 1] μ¬κ³ μμ½
Orchestrator->>InventoryService: reserveStock()
InventoryService-->>Orchestrator: true
Note over Orchestrator: [Step 2] κ²°μ μ²λ¦¬
Orchestrator->>PaymentService: processPayment()
PaymentService-->>Orchestrator: false (μμ‘ λΆμ‘±)
Note over Orchestrator: 보μ νΈλμμ
μ€ν
Orchestrator->>InventoryService: releaseStock() (보μ)
Orchestrator->>OrderService: cancelOrder()
Note over Orchestrator: Saga μλ£ (κ²°μ μ€ν¨ β μ·¨μ)
- Java 21
- Docker & Docker Compose
- Gradle 8.x (λλ Gradle Wrapper μ¬μ©)
./gradlew clean build -x testdocker-compose up -d# ν°λ―Έλ 1: Eureka Server (λ¨Όμ μ€ν!)
./gradlew :eureka-server:bootRun
# ν°λ―Έλ 2: Inventory Service
./gradlew :inventory-service:bootRun
# ν°λ―Έλ 3: Payment Service
./gradlew :payment-service:bootRun
# ν°λ―Έλ 4: Order Service
./gradlew :order-service:bootRun
# ν°λ―Έλ 5: Saga Orchestrator
./gradlew :saga-orchestrator:bootRun| μλΉμ€ | ν¬νΈ | μ€λͺ |
|---|---|---|
| eureka-server | 8761 | μλΉμ€ λμ€μ»€λ²λ¦¬ Dashboard |
| order-service | 8080 | μ£Όλ¬Έ API |
| payment-service | 8081 | κ²°μ API |
| saga-orchestrator | 8082 | Saga Orchestrator (Temporal Worker) |
| inventory-service | 8083 | μ¬κ³ API |
| Temporal Web UI | 8088 | Workflow λͺ¨λν°λ§ |
| Temporal Server | 7233 | Temporal gRPC |
docker-compose down -vcurl http://localhost:8083/api/inventorycurl -X POST http://localhost:8080/api/orders \
-H "Content-Type: application/json" \
-d '{
"userId": "user-1",
"productId": "PROD-001",
"quantity": 2,
"amount": 50
}'μλ΅:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"userId": "user-1",
"productId": "PROD-001",
"quantity": 2,
"amount": 50,
"status": "PENDING"
}curl http://localhost:8080/api/orders/{orderId}curl -X POST http://localhost:8080/api/orders \
-H "Content-Type: application/json" \
-d '{
"userId": "user-2",
"productId": "PROD-001",
"quantity": 1,
"amount": 200
}'μ μ ν μ‘°ννλ©΄ CANCELED μν:
{
"id": "...",
"status": "CANCELED"
}http://localhost:8761 μμ Eureka Dashboardμ μ μνμ¬:
- λ±λ‘λ μλΉμ€ λͺ©λ‘ νμΈ
- κ° μλΉμ€μ μΈμ€ν΄μ€ μν νμΈ
- μλΉμ€ ν¬μ€ 체ν¬
- ORDER-SERVICE
- PAYMENT-SERVICE
- INVENTORY-SERVICE
- SAGA-ORCHESTRATOR
http://localhost:8088 μμ Temporal Web UIμ μ μνμ¬:
- Workflow λͺ©λ‘ νμΈ: μ€ν μ€μΈ/μλ£λ Workflow λͺ©λ‘
- Workflow μμΈ λ³΄κΈ°: κ° Activity μ€ν μ΄λ ₯, μ λ ₯/μΆλ ₯ κ°
- Timeline 보기: Saga κ° λ¨κ³μ μκ° νλ¦
order-{orderId}ννλ‘ μμ±λ¨
- μλΉμ€ μλ λ±λ‘/ν΄μ
- λ‘λ λ°Έλ°μ± μ§μ
- μλΉμ€ ν¬μ€ 체ν¬
- μ£Όλ¬Έ μμ± μ μ¬κ³ νμΈ (λκΈ°)
- μ μΈμ REST ν΄λΌμ΄μΈνΈ
- Fallback μ²λ¦¬ μ§μ
- 3λ¨κ³ Saga: μ¬κ³ μμ½ β κ²°μ β μ£Όλ¬Έ μλ£
- μλ 보μ νΈλμμ
- μν μμμ± λ° μ¬μλ μ²λ¦¬
- λ©±λ±μ±: μ¬κ³ μμ½, κ²°μ μμ²μ μ€λ³΅ μ²λ¦¬ λ°©μ§
- νμμμ: Activityλ³ μ μ ν νμμμ μ€μ
- μ¬μλ μ μ± : μλΉμ€λ³ μ¬μλ μ λ΅
- λͺ¨λν°λ§: Prometheus, Grafana μ°λ
- 보μ: mTLS, μΈμ¦/μΈκ°
- λ‘κΉ : λΆμ° μΆμ (Jaeger, Zipkin)