--- id: wiki-2026-0508-mediator-topology title: Mediator Topology category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Event Mediator Topology, Mediator-Based Event-Driven Architecture] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [event-driven, architecture-topology, orchestration] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: typescript framework: temporal --- # Mediator Topology ## 매 한 줄 > **"매 central orchestrator 가 매 multi-step event flow 를 직접 지휘"**. Mark Richards, *Software Architecture Patterns* — Event-Driven Architecture 의 두 topology 중 하나 (다른 하나는 Broker). Mediator 는 매 sequence + error handling + transactional rollback 이 필요한 매 complex workflow 에 적합. 2026 의 modern 구현: Temporal, AWS Step Functions, Camunda 8, Netflix Conductor. ## 매 핵심 ### 매 Mediator vs Broker (Richards 의 dichotomy) - **Broker**: 매 chain of events, decentralized, 매 service 가 매 다음 step 결정. Pub/sub. 매 simple, fast, hard-to-orchestrate complex workflow. - **Mediator**: 매 central event mediator 가 매 process 를 orchestrate. 매 sequence 명시, 매 error handling 중앙화. 매 complex but observable. ### 매 Mediator components 1. **Event Queue**: incoming initial events. 2. **Event Mediator**: 매 process orchestrator (workflow engine). 3. **Event Channel**: mediator → processor 의 dispatch. 4. **Event Processor**: 매 single step 실행 (idempotent worker). ### 매 응용 (when to use mediator) 1. Order fulfillment (validate → pay → reserve → ship → notify). 2. Loan approval (multi-stage with human-in-loop). 3. Subscription onboarding. 4. ETL/data pipeline with retries and DLQ. 5. SAGA pattern compensation orchestration. ### 매 trade-off vs Broker - **More observable**: 매 mediator 의 single source of truth for workflow state. - **More coupled**: 매 mediator 의 process knowledge — 매 evolution 시 central change. - **Lower throughput**: 매 mediator 의 single point. - **Easier to reason**: 매 sequence 가 명시 — debugging. ## 💻 패턴 ### 1. Temporal workflow (mediator, 2026 standard) ```typescript // activities.ts (event processors) export async function validateOrder(o: Order) { /* ... */ } export async function chargePayment(o: Order) { /* ... */ } export async function reserveInventory(o: Order) { /* ... */ } export async function ship(o: Order) { /* ... */ } export async function notify(userId: string) { /* ... */ } // workflow.ts (mediator) import { proxyActivities } from "@temporalio/workflow"; import type * as activities from "./activities"; const acts = proxyActivities({ startToCloseTimeout: "1 minute", retry: { maximumAttempts: 5 }, }); export async function orderWorkflow(order: Order) { await acts.validateOrder(order); try { await acts.chargePayment(order); await acts.reserveInventory(order); await acts.ship(order); } catch (err) { // SAGA compensation await acts.refundPayment(order).catch(() => {}); await acts.releaseInventory(order).catch(() => {}); throw err; } await acts.notify(order.userId); } ``` ### 2. AWS Step Functions (managed mediator) ```json { "StartAt": "Validate", "States": { "Validate": { "Type": "Task", "Resource": "...:validate", "Next": "Charge" }, "Charge": { "Type": "Task", "Resource": "...:charge", "Catch": [{ "ErrorEquals": ["PaymentError"], "Next": "Refund" }], "Next": "Reserve" }, "Reserve": { "Type": "Task", "Resource": "...:reserve", "Next": "Ship" }, "Ship": { "Type": "Task", "Resource": "...:ship", "Next": "Notify" }, "Notify": { "Type": "Task", "Resource": "...:notify", "End": true }, "Refund": { "Type": "Task", "Resource": "...:refund", "Next": "Fail" }, "Fail": { "Type": "Fail" } } } ``` ### 3. Camunda 8 (BPMN mediator) ```xml ``` ### 4. Custom mediator (lightweight) ```typescript type Step = { name: string; run: (s: S) => Promise; compensate?: (s: S) => Promise }; class Mediator { constructor(private steps: Step[]) {} async execute(initial: S): Promise { const completed: Step[] = []; let state = initial; try { for (const step of this.steps) { state = await step.run(state); completed.push(step); } return state; } catch (err) { // SAGA compensate in reverse for (const step of completed.reverse()) { await step.compensate?.(state).catch(() => {}); } throw err; } } } const orderMediator = new Mediator([ { name: "validate", run: validateOrder }, { name: "charge", run: chargePayment, compensate: refundPayment }, { name: "reserve", run: reserveInventory, compensate: releaseInventory }, { name: "ship", run: ship }, ]); ``` ### 5. Broker (contrast — for comparison) ```typescript // No central mediator. Each service publishes its own next event. // order-service: emits "order.validated" // payment-service: subscribes "order.validated" → publishes "order.paid" // inventory-service: subscribes "order.paid" → publishes "inventory.reserved" // shipping-service: subscribes "inventory.reserved" → publishes "order.shipped" // // Pros: decoupled, scalable // Cons: workflow knowledge scattered, hard to add/reorder steps ``` ### 6. Compensation pattern (SAGA) ```typescript // Within mediator, each step has forward + compensating action const steps = [ { do: chargePayment, undo: refundPayment }, { do: reserveInventory, undo: releaseInventory }, { do: scheduleShipment, undo: cancelShipment }, ]; async function saga(state: S) { const done: typeof steps = []; for (const s of steps) { try { await s.do(state); done.push(s); } catch { for (const d of done.reverse()) await d.undo(state).catch(() => {}); throw new Error("saga compensated"); } } } ``` ### 7. Idempotency (essential for mediator workers) ```typescript async function chargePayment(order: Order) { const idempotencyKey = `charge:${order.id}`; const existing = await db.idempotency.findOne(idempotencyKey); if (existing) return existing.result; const result = await stripe.charges.create({ amount: order.amount, customer: order.customerId, idempotency_key: idempotencyKey, }); await db.idempotency.put(idempotencyKey, result); return result; } // Mediator may retry → worker MUST be idempotent. ``` ## 매 결정 기준 | 상황 | Topology | |---|---| | <5 step linear flow, simple notify | Broker (pub/sub). | | Multi-step with rollback / SAGA | Mediator. | | Long-running (hours/days) workflow | Mediator (Temporal/Step Functions). | | Human approval steps | Mediator (BPMN — Camunda). | | High-throughput stream (>10k/s) | Broker (Kafka). | | Audit + visibility critical | Mediator. | | Loose coupling priority | Broker. | **기본값**: complex business process 는 매 Mediator (Temporal). Simple notification/log 는 매 Broker (Kafka/SNS). ## 🔗 Graph - 부모: [[Event-Driven Architecture]] - 변형: [[Broker Topology]] - 응용: [[Temporal]] - Adjacent: [[Idempotency]] ## 🤖 LLM 활용 **언제**: workflow architecture choice, SAGA design, multi-step business process modeling, retry/compensation strategy. **언제 X**: 매 simple fire-and-forget event, 매 high-throughput streaming (broker preferred). ## ❌ 안티패턴 - **God mediator**: 매 매 모든 process 가 매 single mediator 에 — 매 monolith of orchestration. 매 domain 별 분리. - **Non-idempotent worker**: 매 mediator retry → 매 double-charge / double-ship. 매 idempotency key 필수. - **Mediator knows business rules**: 매 if/else 분기 가 매 mediator 에 — workflow engine 의 limit. 매 decision 은 activity 로 push. - **Sync mediator for slow steps**: 매 mediator 가 매 slow IO 의 inline wait — 매 timeout. 매 async + signal/callback. - **No timeout/retry policy**: 매 hung workflow 의 매 stuck instance. - **Compensation 누락**: 매 SAGA 의 매 partial commit 의 매 inconsistent state. ## 🧪 검증 / 중복 - Verified (Richards, *Software Architecture Patterns* O'Reilly 2015; Temporal docs; Hohpe & Woolf, *Enterprise Integration Patterns* — Process Manager). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — Mediator vs Broker + Temporal/Step Functions/Camunda 2026 implementations |