---
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<typeof activities>({
  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
<!-- order.bpmn (visual model, executable) -->
<bpmn:process id="orderProcess">
  <bpmn:startEvent id="OrderReceived" />
  <bpmn:serviceTask id="Validate" zeebe:type="validate-order" />
  <bpmn:serviceTask id="Charge"  zeebe:type="charge-payment" />
  <bpmn:exclusiveGateway id="ChargeOk?" />
  <bpmn:serviceTask id="Reserve" zeebe:type="reserve-inventory" />
  <!-- ... compensation events for SAGA -->
</bpmn:process>
```

### 4. Custom mediator (lightweight)
```typescript
type Step<S> = { name: string; run: (s: S) => Promise<S>; compensate?: (s: S) => Promise<void> };

class Mediator<S> {
  constructor(private steps: Step<S>[]) {}

  async execute(initial: S): Promise<S> {
    const completed: Step<S>[] = [];
    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<Order>([
  { 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<S>(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 |
