기존 워크플로우 문제점과 Ductwork의 해결책
Ruby의 기존 백그라운드 잡 시스템은 복잡한 다단계 워크플로우를 처리할 때 여러 한계를 드러냅니다.
-
워크플로우 비가시성: 잡, 콜백, 배치 등을 추적해야 전체 흐름을 파악할 수 있어 “이것이 워크플로우다”라고 명확히 보여주는 단일 지점이 없습니다.
-
수동 데이터 전달: 각 잡이 입력 데이터를 어디서 찾아야 하는지 수동으로 관리해야 하며, 프레임워크 차원의 도움을 받기 어렵습니다.
-
어려운 테스트: 특정 잡을 격리하여 테스트하기 위해 전체 배치 인프라를 설정하거나 목업해야 하는 복잡성이 있습니다.
-
분산된 에러 처리: 다양한 실패 시나리오에 대한 사용자 정의 코드가 여러 곳에 분산되어 있어 확장이 어렵습니다.
Ductwork는 이러한 문제들을 다음과 같이 해결합니다.
-
선언적 가시성: 전체 워크플로우가 하나의 파이프라인 DSL 내에서 명확하게 정의되어, 좌우 및 상하로 읽으며 흐름을 쉽게 이해할 수 있습니다.
-
자동화된 조정 및 데이터 전달: DSL이 전환을 정의함으로써 라이브러리가 Step 간의 조정, 데이터 전달, 병렬 실행을 자동으로 처리합니다.
-
격리된 테스트: 각 Step은 단일 책임의 평범한 Ruby 클래스로, 잡 인프라 없이 독립적으로 테스트할 수 있습니다.
-
견고한 에러 처리: 파이프라인 실행 상태가 데이터베이스에 저장되어, 문제가 발생했을 때 현재 상태와 실패 지점을 쉽게 파악하고 디버깅할 수 있습니다.
Ductwork의 핵심 개념
Ductwork는 복잡한 워크플로우를 효율적으로 구축하기 위한 핵심 개념을 제공합니다.
- 파이프라인 DSL:
Chain: 가장 간단한 순차적 전환으로, 이전 Step의 출력이 다음 Step의 입력이 됩니다.Expand/Collapse: 컬렉션을 받아 각 요소에 대해 병렬 Step을 생성(Expand)하고, 모든 병렬 Step 완료 후 결과를 배열로 집계(Collapse)합니다.Divide/Combine: 실행을 여러 병렬 브랜치로 분할(Divide)하고, 모든 브랜치 완료 후 다시 병합(Combine)합니다.
- Step:
Ductwork::Step을 상속받고execute메서드를 구현하는 평범한 Ruby 클래스입니다. 단일 목적, 자체 포함적이며 테스트가 용이합니다.
- 데이터 흐름 및 전역 컨텍스트:
- 반환 값 (Step-to-Step): Step의 반환 값이 다음 Step의 입력이 됩니다.
- 전역 컨텍스트 (Pipeline-wide): 모든 Step에서 접근 가능한 키/값 저장소로, 파이프라인 전체에서 필요한 공통 데이터를 저장합니다.