패턴 카탈로그
모든 워크플로우를 위한 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)