Skip to content

ADR 0002 Portal Job Outbox and SQS

SANGMIN PARK edited this page Jul 17, 2026 · 1 revision

ADR-0002. 포털 작업을 Job·Outbox·SQS로 분리

  • 상태: Accepted
  • 결정일: 2026-03-14
  • 마지막 검증: 2026-07-18

맥락

수원대학교 포털 로그인과 학사 데이터 수집은 외부 시스템의 응답 시간과 장애에 영향을 받습니다. API 요청 스레드에서 스크래핑 전체를 수행하면 timeout과 중복 요청에 취약합니다.

DB에 작업만 저장한 뒤 SQS 발행이 실패하거나, SQS에만 발행한 뒤 DB 저장이 실패하면 작업 상태와 실제 메시지가 어긋날 수 있습니다. 포털 자격 증명을 포함한 같은 요청이 재시도될 때 중복 Worker 실행도 막아야 합니다.

결정

  1. 포털 연동 요청은 장기 작업으로 취급하고 202 AcceptedjobId를 반환합니다.
  2. scrape_jobsscrape_job_outbox를 같은 DB 트랜잭션에 저장합니다.
  3. 사용자와 Idempotency-Key로 기존 Job을 찾고 요청 fingerprint가 다르면 충돌로 거부합니다.
  4. DB 커밋 후 해당 Outbox를 SQS에 동기 발행하고, Outbox가 SENT, Job이 RUNNING인지 확인한 뒤 요청을 성공으로 반환합니다.
  5. Worker는 SQS 메시지를 소비해 포털 작업을 수행하고 Backend는 Job 조회 API로 상태를 제공합니다.
  6. Outbox는 PENDING, RETRYABLE_FAILED, SENT, DEAD 상태와 시도 횟수, 다음 시도 시각, 마지막 오류를 저장합니다.

검토한 대안

API에서 포털을 동기 호출

구현은 단순하지만 외부 포털의 지연이 API timeout과 Lambda 실행 시간으로 전파됩니다. 클라이언트 재시도도 실제 작업 중복으로 이어질 수 있습니다.

DB 기록 없이 SQS에 직접 발행

DB와 Queue 사이의 원자성을 보장할 수 없고, 메시지 발행 후 API가 실패하면 클라이언트와 서버가 작업 존재 여부를 다르게 인식합니다.

Outbox 저장 직후 발행 결과를 확인하지 않고 응답

API 응답은 빨라지지만 현재 운영 경로에는 dispatchEligibleOutboxes()를 주기적으로 호출하는 코드가 없습니다. 자동 릴레이가 없는 상태에서 Job이 QUEUED에 고립될 수 있어 채택하지 않았습니다.

결과

장점

  • Job과 발행할 메시지가 하나의 DB 트랜잭션으로 보존됩니다.
  • 같은 Idempotency Key와 같은 요청은 기존 Job을 재사용합니다.
  • 202 응답 시점에 SQS 발행 성공을 확인하므로 즉시 발행 실패를 호출자에게 알릴 수 있습니다.
  • jobId, outboxId, Queue Message ID로 API부터 Worker까지 추적할 수 있습니다.

비용과 제약

  • 요청 응답 시간이 DB 저장뿐 아니라 SQS 발행 시간에도 영향을 받습니다.
  • Outbox payload에 포털 자격 증명이 포함되므로 DB 접근, 로그, 운영 조회를 엄격히 제한해야 합니다.
  • RETRYABLE_FAILED 상태는 저장되지만 현재 자동 배치 호출부가 없습니다. 자동 백그라운드 재처리를 전제로 운영하면 안 됩니다.
  • DB와 SQS를 함께 운영하고 상태 전이를 관리해야 하므로 단순 Queue 발행보다 구현이 복잡합니다.

운영 규칙

  • Outbox payload와 Job request payload를 로그, Issue, 일반 운영 SQL 결과에 포함하지 않습니다.
  • 같은 Idempotency Key에 다른 요청을 보내면 C07 IDEMPOTENCY_KEY_CONFLICT로 처리합니다.
  • QUEUED 장애는 Job과 Outbox 상태를 함께 확인하고 DB 상태만 수동 변경하지 않습니다.
  • Worker 메시지 계약을 바꾸면 Backend 발행 DTO와 Worker 소비 코드를 함께 배포합니다.

재검토 조건

  • EventBridge Scheduler나 별도 Relay가 dispatchEligibleOutboxes()를 안정적으로 실행하게 됩니다.
  • 포털 자격 증명을 일회성 Token이나 별도 보안 저장소 참조로 대체합니다.
  • SQS 발행 지연이 API 응답 목표를 지속해서 위반합니다.

근거

Clone this wiki locally