Skip to content

ADR-12: Worker 중심 분석 라이프사이클 ​

🇺🇸 English Version

날짜작성자리포지토리
2024-12-16@KubrickCodeweb, worker

배경 ​

기존 아키텍처 ​

ADR-03에서 API(Web)와 Worker 서비스 분리 확립. ADR-04에서 큐 기반 비동기 처리 도입. 초기 구현의 이중 소유권 문제 발생:

기존 흐름:

사용자 요청 → Web이 "pending" 레코드 생성 → Enqueue → Worker 처리 → 레코드 업데이트

문제: 두 서비스가 동일한 데이터베이스 레코드 조작

이중 소유권의 문제점 ​

문제영향
중복 레코드Web이 pending 레코드 생성, Worker도 별도 레코드 생성 가능
상태 불일치Web의 DB 상태와 실제 큐 상태 불일치 가능성
복잡한 에러 복구실패 시 두 서비스 간 조율 필요
경쟁 조건재시도 요청으로 다수 pending 레코드 생성 가능
불명확한 책임레코드 상태의 권위 있는 소스 모호

근본 원인 ​

핵심 문제: 분석 레코드 라이프사이클에 대한 단일 진실 공급원(Single Source of Truth) 부재. Web과 Worker 모두 동일 레코드에 쓰기 권한 보유로 동기화 복잡성 야기.

결정 ​

Worker가 레코드 생성, 처리, 완료를 독점적으로 소유하는 Worker 중심 분석 라이프사이클 채택.

새로운 아키텍처 ​

사용자 요청 → Web (enqueue만) → Queue → Worker (생성 → 처리 → 완료)
                    ↓                              ↓
              UUID 생성                    레코드 라이프사이클 단일 소유
              큐에서 상태 확인             작업 시작 시 레코드 생성
                                          완료/실패 시 업데이트

핵심 원칙:

  1. Web: Enqueue만 - 분석 UUID 생성, 작업 enqueue, 분석 테이블에 쓰기 금지
  2. Worker: 전체 소유 - 작업 시작 시 레코드 생성, 완료 시 업데이트
  3. Queue가 상태 소스 - Web은 진행 중 분석을 DB가 아닌 큐에서 확인
  4. 단일 Writer - Worker만 분석 레코드에 쓰기

검토한 옵션 ​

옵션 A: Worker 중심 소유권 (선택) ​

Web이 생성된 UUID와 함께 분석 요청 enqueue. Worker가 처리 시작 시 레코드 생성, 완료 시 갱신.

장점:

  • 단일 진실 공급원: 하나의 서비스가 전체 라이프사이클 소유
  • 중복 레코드 없음: Worker만 분석 항목 생성
  • 명확한 서비스 경계: Web은 HTTP, Worker는 분석 담당
  • 단순한 에러 처리: 모든 실패 상태를 한 곳에서 관리
  • 트랜잭션 일관성 향상: 동일 서비스 컨텍스트에서 생성과 업데이트
  • 독립적 확장: Worker가 Web에 영향 없이 확장 가능

단점:

  • Web이 상태 조회를 위해 큐에 의존
  • 큐 시스템이 중요 인프라로 격상
  • 상태 확인 로직 복잡성 증가

옵션 B: Web 중심 소유권 ​

Web이 모든 레코드 생성 및 관리. Worker는 기존 레코드만 업데이트.

장점:

  • 추적을 위한 즉각적인 DB 레코드
  • 단순한 상태 조회 (항상 DB에서)

단점:

  • Worker가 "레코드 없음" 케이스 처리 필요
  • DB 커밋 전 큐 처리 시 타이밍 문제 발생
  • 재시도 로직 복잡화 (레코드 존재 여부 확인 필요)
  • Web이 레코드 생성 병목으로 작용

옵션 C: 이중 소유권 (기존) ​

두 서비스가 조율 로직으로 레코드 생성 및 수정 가능.

장점:

  • 구현의 유연성

단점:

  • 중복 레코드 위험
  • 복잡한 조율 필요
  • 분산 트랜잭션과 유사한 복잡성
  • 진실 공급원 모호성

구현 상세 ​

Queue Payload ​

json
{
  "owner": "github-org",
  "repo": "repo-name",
  "commit_sha": "abc123",
  "user_id": "uuid",
  "analysis_id": "uuid"
}
  • analysis_id: Web에서 미리 생성

상태 조회 흐름 (Web) ​

  1. owner/repo와 일치하는 활성 작업이 큐에 있는지 확인
  2. 활성 작업 발견 → "pending" 상태 반환
  3. 활성 작업 없음 → DB에서 완료/실패 분석 조회

중복 제거 ​

CommitSHA 기반 고유성으로 중복 분석 방지:

  • 동일 repo+commit에 대한 다중 요청 → 단일 큐 작업
  • River의 (owner, repo, commit_sha) 유니크 제약
  • 동시 요청 시 불필요한 연산 방지

결과 ​

긍정적 ​

데이터 무결성:

  • 중복 분석 레코드 없음
  • 일관된 라이프사이클 상태 머신
  • 명확한 소유권으로 경쟁 조건 제거

운영 단순성:

  • 분석 문제 디버깅을 위한 단일 서비스
  • 명확한 로그와 트레이스
  • 단순한 모니터링 (추적할 writer가 하나)

확장성:

  • Worker가 큐 깊이에 따라 독립적으로 확장
  • Web은 가벼움 유지 (분석용 무거운 DB 쓰기 없음)
  • 큐가 자연스럽게 부하 버퍼링

미래 호환성:

  • 예약 재분석과 정렬 (Worker ADR-01)
  • 사용자 시작이든 예약이든 동일한 라이프사이클
  • 일관된 소유권 모델

부정적 ​

큐 의존성:

  • Web이 상태를 위해 큐 조회 필요
  • 큐 불가용 시 상태 조회에 영향
  • 완화책: 큐가 PostgreSQL 백엔드 공유 (River), DB와 동일한 가용성

지연된 가시성:

  • Worker가 처리 시작할 때까지 분석이 DB에 미노출
  • enqueue와 레코드 생성 사이 짧은 지연
  • 완화책: 큐 상태가 즉각적인 피드백 제공

복잡성 이동:

  • 상태 로직이 단순 DB 조회에서 큐 검사로 이동
  • 완화책: repository/adapter 레이어에 캡슐화

기술적 함의 ​

측면함의
트랜잭션 범위레코드 생성 + 초기 상태가 단일 Worker 트랜잭션에서
실패 처리모든 재시도가 Worker에서 관리
큐 스키마상태를 위한 owner/repo 조회 지원 필요
모니터링큐 메트릭이 분석 상태 표시
예약 분석사용자 시작과 예약 분석이 동일한 라이프사이클

참고자료 ​

Open-source test coverage insights