패턴 카탈로그

모든 워크플로우를 위한 12가지 패턴.

검증된 Ranvier 패턴의 빠른 참조 카탈로그입니다. 각 카드는 최소한의 코드 예제와 전체 예제 링크를 포함합니다.

1. 기본 파이프라인

초급

트랜지션을 선형으로 체이닝하여 처리 파이프라인을 구축합니다.

let axon = Axon::simple::<String>("pipeline")
    .then(ValidateInput)
    .then(ProcessData)
    .then(FormatOutput);

let result = axon.execute(input, &(), &mut bus).await;

예제: hello-world, typed-state-tree

2. 리소스 주입

초급

Resources를 통해 공유 의존성(DB 풀, 설정)을 주입합니다.

impl ResourceRequirement for DbPool {}

impl Transition<UserId, User> for FetchUser {
    type Resources = DbPool;

    async fn run(&self, id: UserId, pool: &DbPool, _bus: &mut Bus)
        -> Outcome<User, String> {
        Outcome::Next(pool.query_user(&id).await)
    }
}

예제: db-example, multitenancy-demo

3. Bus 역량 주입

초급

타입 인덱스 기반 Bus를 통해 요청별 컨텍스트를 파이프라인에 전달합니다.

bus.insert(RequestId("req-abc".into()));
bus.insert(TenantId::new("tenant-1"));

// 트랜지션 내부에서
let tenant = bus.read::<TenantId>();
let req_id = bus.read::<RequestId>();

예제: bus-capability-demo, multitenancy-demo

4. 커스텀 에러

중급

thiserror + serde로 구조화된 도메인 에러를 정의합니다.

#[derive(Error, Serialize, Deserialize)]
enum OrderError {
    #[error("찾을 수 없음: {0}")]
    ItemNotFound(String),
    #[error("결제 거절: {0}")]
    PaymentDeclined(String),
}

예제: custom-error-types, order-processing-demo

5. 분기 처리

중급

Outcome::Branch로 조건부 흐름 분기를 구현합니다.

if order.total > 10_000 {
    return Outcome::Branch(
        "high_value".into(),
        Some(serde_json::to_value(&order).unwrap()),
    );
}
Outcome::Next(order)

예제: order-processing-demo

6. 재시도 + DLQ

중급

지수 백오프 자동 재시도와 데드 레터 큐 폴백을 설정합니다.

axon.with_dlq_policy(DlqPolicy::RetryThenDlq {
    max_attempts: 3,
    backoff_ms: 100,
})
.with_dlq_sink(InMemoryDlqSink::new());

예제: retry-dlq-demo

7. 영속성

고급

워크플로우 상태를 영속화하여 장애 복구 및 체크포인트/재개를 지원합니다.

let mut bus = ranvier_bus!(
    handle.clone(),
    PersistenceTraceId::new("trace-001"),
    PersistenceAutoComplete(false),
);
let result = axon.execute(input, &(), &mut bus).await;

예제: state-persistence-demo

8. 보상 & 롤백

고급

보상 훅을 등록하여 장애 시 자동 롤백합니다 (사가 패턴).

impl CompensationHook for RefundPayment {
    async fn compensate(&self, ctx: CompensationContext)
        -> anyhow::Result<()> {
        println!("환불 처리 trace={}", ctx.trace_id);
        Ok(())
    }
}

예제: state-persistence-demo (3단계)

9. 테넌트 격리

중급

멀티테넌시 확장의 TenantId로 테넌트별 데이터를 격리합니다.

bus.insert(TenantId::new("tenant-a"));

// Inside transition
let tenant = bus.read::<TenantId>()
    .ok_or_else(|| "missing tenant".to_string())?;
let data = store.list(tenant.as_str()).await;

예제: multitenancy-demo

10. 단위 테스트

초급

트랜지션은 비동기 함수입니다 — 직접 테스트하거나 전체 파이프라인을 테스트하세요.

#[tokio::test]
async fn test_pipeline() {
    let result = axon.execute(input, &(), &mut bus).await;
    assert!(result.is_next());
}

예제: testing-patterns (7개 테스트)

11. 서킷 브레이커

고급

공유 원자적 상태를 사용한 애플리케이션 레벨 서킷 브레이커.

let failures = self.failure_count.load(Ordering::SeqCst);
if failures >= self.threshold {
    return Outcome::Fault("circuit open".to_string());
}

예제: retry-dlq-demo (데모 5)

12. 타임아웃

중급

tokio::time::timeout으로 느린 작업을 래핑합니다.

match timeout(Duration::from_millis(500), slow_op(&input)).await {
    Ok(Ok(result)) => Outcome::Next(result),
    Ok(Err(e)) => Outcome::Fault(e.to_string()),
    Err(_) => Outcome::Fault("timed out".to_string()),
}

예제: retry-dlq-demo (데모 3-4)

전체 카탈로그와 완전한 코드: 패턴 카탈로그