2026년 나의 첫 Vapor 백엔드에 백그라운드 작업과 메타데이터 가져오기 추가하기 (6)
Add Background Jobs and Metadata Fetching to My First Vapor Backend in 2026 pt. 6
핵심 요약
- 링크 생성 요청은 링크와 태그를 저장한 뒤 메타데이터 작업을 큐에 전달하며, 외부 사이트 응답을 기다리지 않고 사용자 응답을 반환한다.
- Vapor Queues와 Redis로 작업을 보관하고 별도 worker가 처리한다. 작업 payload에는 링크 ID만 담아 worker가 데이터베이스에서 최신 링크를 다시 조회한다.
- 작업은 메타데이터 상태를 fetching, fetched, failed로 기록하며, HTML에서 제목·설명·이미지 URL·사이트 이름을 추출해 링크 레코드를 갱신한다.
도입
LinkVault의 링크 생성 과정에 백그라운드 메타데이터 수집을 추가한다. 외부 웹사이트 요청은 지연되거나 실패할 수 있으므로 API 요청 안에서 처리하지 않는다. 링크를 먼저 저장하고 Redis 기반 Vapor Queues에 작업을 전달한 뒤, 별도 worker가 페이지 HTML을 가져와 메타데이터를 저장한다. 이로써 메타데이터 수집이 사용자 요청을 기다리게 하지 않는다.
상세 요약
링크 저장과 메타데이터 수집 분리
기존 LinkVault는 사용자가 보낸 제목, URL, 메모, 읽음 상태, 컬렉션, 태그를 저장한다. 여기에 페이지 제목, 설명, Open Graph 이미지, 사이트 이름, 메타데이터 상태와 수집 시각을 추가한다. 외부 사이트에 HTTP 요청을 보내고 HTML을 처리하는 작업은 느리거나 실패할 수 있으므로 링크 생성 요청을 막지 않도록 별도 큐 작업으로 옮긴다.
Link 모델에는 metadataTitle, metadataDescription, metadataImageURL, metadataSiteName, metadataStatus, metadataFetchedAt 필드를 추가한다. AddMetadataToLink 마이그레이션은 links 테이블에 대응하는 컬럼을 추가하고, 되돌릴 때는 해당 컬럼을 삭제한다. 필드가 아직 비어 있으면 Optional 값이므로 초기 응답 JSON에는 나타나지 않는다. LinkResponse에도 메타데이터 필드를 포함해 작업 완료 후 클라이언트가 조회할 수 있게 한다.
Redis와 Vapor Queues 구성
로컬 개발 환경에 Redis 서비스를 추가하고 queues-redis-driver 패키지를 연결한다. Vapor 설정에서 REDIS_URL 환경 변수를 사용하며, 값이 없으면 redis://127.0.0.1:6379를 기본 주소로 쓴다. FetchLinkMetadataJob을 큐에 등록한다. Redis는 worker가 처리하기 전까지 작업을 보관한다.
작업 payload는 Codable을 준수하는 FetchLinkMetadataPayload이며, linkID만 담는다. 전체 Link 객체를 전달하는 대신 worker가 데이터베이스에서 링크를 다시 불러온다. 따라서 작업에는 필요한 식별자만 들어가며, 처리 시점의 링크 데이터를 기준으로 한다.
작업 처리와 상태 기록
FetchLinkMetadataJob은 링크를 조회한 뒤 상태를 fetching으로 저장한다. 이후 링크 URL에 HTTP GET 요청을 보내고 응답 본문을 HTML 문자열로 읽는다. 응답 상태가 성공이 아니거나 본문을 읽을 수 없으면 상태를 failed로 바꾸고 수집 시각을 기록한다. 요청 중 예외가 발생해도 실패 상태와 시각을 저장하고 오류를 로그에 남긴 뒤 예외를 다시 던진다.
HTML 파서는 og:title, og:description, description, og:image, og:site_name 패턴을 찾는다. 추출 결과는 링크의 메타데이터 필드에 저장되고 상태는 fetched가 된다. 이 파서는 튜토리얼 목적의 단순한 구현이다.
생성 요청과 worker 실행
링크를 저장하고 태그를 연결한 다음 req.queue.dispatch로 작업을 전달한다. payload에는 저장한 링크의 ID가 들어가며 maxRetryCount는 3으로 지정한다. 작업 처리는 swift run LinkVault queues로 실행하는 worker가 맡는다. 애플리케이션은 swift run 또는 Xcode에서 별도로 실행한다.
worker가 동작 중이면 링크 생성 뒤 작업이 실행되고, 이후 링크 조회 응답에서 메타데이터와 fetched 상태를 확인할 수 있다. worker가 꺼져 있어도 작업은 Redis에 대기하며, API는 링크를 저장하고 응답을 반환한다. worker를 다시 시작하면 대기 중인 작업을 처리한다. 즉 API는 작업을 전달하고, Redis는 작업을 보관하며, worker는 실제 처리를 수행한다.
이 구현은 고급 HTML 파싱, 상대 이미지 URL 처리, favicon 대체, 도메인별 요청 제한, robots.txt, 메타데이터 갱신 예약, 중복 작업 방지, 실패 유형별 재시도 정책, 별도 메타데이터 테이블을 포함하지 않는다. 다음 편의 테스트 구성은 Vapor 백엔드 배포 전 핵심 동작을 테스트하기에서 이어진다.
결론
이 구현은 큐 드라이버 설정, 작업 등록, 링크 ID payload, 상태 기록, 별도 worker 실행으로 구성된다. worker가 중지된 동안에도 작업은 Redis에 남아 재시작 후 처리할 수 있다. 다만 HTML 파싱은 단순하며 상대 이미지 URL, favicon 대체, 도메인별 요청 제한, 중복 작업 방지 등은 다루지 않는다.