--- id: wiki-2026-0508-choreography title: Choreography category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Event Choreography, Saga Choreography] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [microservices, distributed-systems, events, saga] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: typescript framework: kafka-temporal --- # Choreography ## 매 한 줄 > **"매 service 가 자기 part 의 dance step 을 알고 events 으로 react — 매 central conductor 없음."**. Choreography는 distributed workflow를 events 의 emit/subscribe 로 구현하는 pattern. Orchestration 의 반대 — 매 decoupling 매 high, 매 visibility 매 low. 2026년 event-driven microservices, EDA, Saga pattern 의 핵심 선택지. ## 매 핵심 ### 매 Choreography vs Orchestration | 측면 | Choreography | Orchestration | |---|---|---| | Control | Distributed | Centralized (orchestrator) | | Coupling | Low (events) | Higher (orchestrator knows all) | | Visibility | Hard (trace tools 필요) | Easy (one workflow definition) | | Add new step | Just subscribe | Edit orchestrator | | Failure handling | Each service handles own | Orchestrator decides | | Examples | Kafka events, NATS | Temporal, AWS Step Functions | ### 매 패턴 종류 - **Event-carried state transfer**: event 가 모든 필요 data 포함. - **Event notification**: event 는 trigger only, state 는 query. - **Saga choreography**: distributed transaction 의 compensating events. ### 매 응용 1. E-commerce order flow (OrderCreated → Payment → Shipping events). 2. User signup pipeline (UserRegistered → emails → analytics). 3. IoT event processing (sensor → multiple consumers). 4. Domain events (DDD bounded context integration). ## 💻 패턴 ### Saga choreography (TypeScript + Kafka) ```typescript // Order service async function createOrder(req: CreateOrderRequest) { const order = await db.orders.insert({ ...req, status: 'pending' }); await kafka.produce('order.created', { orderId: order.id, userId: order.userId, amount: order.total, }); return order; } // Order service also listens for compensations kafka.consume('payment.failed', async (evt) => { await db.orders.update(evt.orderId, { status: 'cancelled' }); await kafka.produce('order.cancelled', { orderId: evt.orderId }); }); ``` ### Payment service reacts independently ```typescript kafka.consume('order.created', async (evt) => { try { const charge = await stripe.charges.create({ amount: evt.amount * 100, customer: evt.userId, }); await kafka.produce('payment.succeeded', { orderId: evt.orderId, chargeId: charge.id, }); } catch (err) { await kafka.produce('payment.failed', { orderId: evt.orderId, reason: String(err), }); } }); ``` ### Shipping service ```typescript kafka.consume('payment.succeeded', async (evt) => { const shipment = await shippingApi.create({ orderId: evt.orderId }); await kafka.produce('shipment.created', { ...shipment }); }); ``` ### Event schema (Avro / JSON Schema) ```json { "type": "record", "name": "OrderCreated", "fields": [ { "name": "orderId", "type": "string" }, { "name": "userId", "type": "string" }, { "name": "amount", "type": "double" }, { "name": "createdAt", "type": "string" } ] } ``` ### Idempotent consumer ```typescript async function handleOrderCreated(evt: OrderCreated) { // Dedup by event id const seen = await redis.set( `processed:${evt.eventId}`, '1', { NX: true, EX: 86400 }, ); if (!seen) return; // already processed await processOrder(evt); } ``` ### Distributed tracing (OTel) 매 visibility 회복 ```typescript import { trace, context, propagation } from '@opentelemetry/api'; async function publishWithTrace(topic: string, evt: any) { const span = trace.getActiveSpan(); const carrier: Record = {}; propagation.inject(context.active(), carrier); await kafka.produce(topic, { ...evt, _trace: carrier, }); } ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Simple linear workflow | Orchestration (Temporal) | | Many independent reactors | Choreography | | Strong consistency 필요 | Orchestration + 2PC 또는 Temporal | | Fan-out events | Choreography | | Need visual workflow + retry | Orchestration | | Event-driven domain (DDD) | Choreography | **기본값**: 매 simple 2-3 step domain workflow → orchestration (Temporal). 매 broad fan-out + autonomous teams → choreography. ## 🔗 Graph - 부모: [[Event-Driven Architecture]] · [[Microservices]] - 변형: [[Pub-Sub]] - 응용: [[Broker Topology]] · [[Event Sourcing]] - Adjacent: [[Orchestration]] · [[CQRS]] ## 🤖 LLM 활용 **언제**: event-driven microservice design, decoupling teams, fan-out workflows, autonomous services. **언제 X**: short transactional flow needing visibility, strict ordering 필요한 critical financial workflows (orchestrator + Temporal 가 better). ## ❌ 안티패턴 - **Distributed monolith via events**: events 가 actually RPC 호출 — coupling 그대로. - **No event versioning**: schema 변경 시 모든 consumer 깨짐 — Schema Registry 필수. - **Lost trace**: span 이 event boundary 에서 끊김 — propagation injection 필수. - **Implicit ordering assumption**: 매 services 가 임의 order 로 react — explicit ordering 필요 시 partition key. ## 🧪 검증 / 중복 - Verified (Hohpe "Enterprise Integration Patterns" / Microservices.io / Confluent docs 2026). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — Saga choreography + Kafka + OTel 패턴 |