개발 slecs

결제 전후 PDF 추출을 동기·비동기로 분리해 미리보기 속도 개선

목차

PDF 기반 데이터 추출 흐름을 둘로 쪼갠 작업을 했다. "결제 전 미리보기"와 "결제 후 전체 익스포트"가 같은 파이프라인을 공유하던 구조에서 벗어나, 각자 맞는 실행 방식으로 분리한 것.

왜 쪼개야 했나

PDF에서 데이터를 뽑는 작업은 생각보다 무겁다. 페이지 수가 늘어날수록 처리 시간이 선형으로 늘어나고, OCR 후처리나 필드 매핑까지 끼면 수십 초가 걸리기도 한다. 그런데 결제 전 미리보기 단계에서 사용자가 원하는 건 사실 "이거 대충 어떻게 생겼나"다. 전체 필드를 완벽하게 추출한 결과가 필요한 게 아니라, 몇 개 핵심 필드만 빠르게 보여주면 된다.

이 둘을 같은 파이프라인으로 처리하면 미리보기 응답이 느려지고, 그게 전환율에 직접 영향을 준다. 팀 내부에서도 "미리보기 너무 오래 걸린다"는 피드백이 반복됐고, 결국 구조적으로 분리하는 게 맞다는 결론을 냈다.

구분 미리보기 (cheap preview) 전체 익스포트 (full export)
실행 방식 동기 (sync) 비동기 (async)
추출 범위 핵심 필드 일부 전체 필드
응답 방식 즉시 반환 잡 큐 → 완료 알림
트리거 결제 전 결제 완료 후
실패 처리 즉시 오류 노출 재시도 큐

실제 변경 포인트

-- sql/migrations/2026-05-27-async-extraction.sql
-- 비동기 익스포트 잡을 추적하기 위한 테이블/컬럼 추가
-- 상태 컬럼(pending / processing / done / failed), 결제 연결 FK 포함

마이그레이션 파일이 이번 작업에서 제일 핵심이다. 비동기 full export는 "잡을 등록하고 끝"이기 때문에, 그 잡의 상태를 DB에서 추적할 구조가 먼저 있어야 했다. 결제 이벤트가 발생하면 잡을 enqueue하고, 워커가 처리 완료하면 상태를 업데이트하는 흐름. 이걸 위한 스키마 기반이 이 마이그레이션에 들어갔다.

package.json / package-lock.json 변경도 있는데, 아마 비동기 처리 혹은 PDF 파싱 경량화 관련 의존성이 추가됐거나 정리됐을 것이다. 이런 의존성 변경은 항상 lock 파일까지 같이 커밋하는 게 원칙 — 리뷰어 입장에서 lock 파일 없는 package.json 변경은 그냥 신뢰 못하는 상태로 본다.

CLAUDE.mddocs/STATUS.md 업데이트는 팀 문서화 측면. 아키텍처가 변경됐으니 현재 상태를 기록하고, AI 컨텍스트용 문서도 갱신한 거다. 이걸 커밋에 같이 넣는 게 귀찮아 보여도, 나중에 "이게 왜 이렇게 됐지?"를 추적할 때 이 diff 하나가 엄청난 시간을 아껴준다.

이런 분리에서 항상 챙겨야 할 것들

비동기 흐름을 새로 도입할 때 팀에서 제일 많이 놓치는 게 실패 시나리오 설계다. 동기는 실패가 즉시 노출되지만, 비동기는 조용히 죽는 경우가 생긴다. 잡이 pending에서 영원히 안 빠져나오거나, 워커가 예외를 삼켜버리는 케이스. 이번 마이그레이션에 failed 상태 컬럼을 명시적으로 넣은 것도 그 때문이다.

  • 잡 타임아웃 기준 명확히 설정
  • failed 상태 진입 조건 + 재시도 횟수 제한
  • 결제는 완료됐는데 잡이 실패한 경우 → 사용자에게 어떻게 알릴지
  • 모니터링: pending 개수가 일정 이상이면 알람

결제와 연결된 비동기 잡은 특히 "결제 완료 이벤트가 두 번 들어오면?" 같은 멱등성 케이스도 반드시 검토해야 한다. 이 부분은 스키마 레벨에서 unique 제약으로 막거나, 잡 등록 전에 이미 존재하는 잡을 체크하는 로직으로 처리하는 게 일반적이다.

미리보기/풀 익스포트 분리는 UX 측면에서도 의미가 있다. 사용자 입장에서 "빠른 미리보기 → 결제 → 백그라운드에서 완성본 생성"이라는 흐름이 훨씬 자연스럽다. 결제를 기다리게 하는 게 아니라, 결제가 트리거가 되는 구조. 이 흐름이 정착되면 나중에 익스포트 포맷을 확장하거나 재처리 기능을 붙일 때도 비동기 잡 레이어만 건드리면 된다.

.gitignore 변경은 아마 로컬 PDF 테스트 파일이나 임시 익스포트 결과물 경로가 추가됐을 것. 이런 작업을 할 때 로컬에 샘플 PDF가 쌓이기 마련이고, 그게 실수로 커밋되는 걸 막는 거다. 사소해 보이지만 팀에서 처음 이 기능을 건드리는 사람이 같은 실수를 안 하게 해주는 작업.

끝.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.