오래 걸리는 작업을 API에서 바로 처리하면 안 되는 이유
보고서 생성, 대량 메일, 이미지 변환, 외부 API 수집을 일반 API 요청 안에서 끝내려 하면 처음에는 단순해 보인다. 하지만 실행 시간이 길어질수록 브라우저, 프록시, 서버리스 함수 중 하나가 먼저 연결을 끊을 가능성이 커진다. 사용자가 다시 누르면 같은 작업이 중복 실행되기도 한다.
오래 걸리는 작업의 핵심은 더 긴 타임아웃이 아니라 요청과 실행을 분리하는 것이다.
요청과 작업을 분리한다
권장 흐름은 다음과 같다.
- 사용자가 작업을 요청한다.
- API는 권한과 입력을 확인하고 작업 레코드를 만든다.
- 큐에 작업 ID를 넣고 즉시 202 Accepted와 작업 ID를 반환한다.
- 워커가 큐에서 작업을 가져와 처리한다.
- 결과와 진행 상태를 DB에 기록한다.
- 화면은 Polling, SSE 또는 실시간 알림으로 상태를 확인한다.
이 구조에서는 브라우저를 닫아도 작업이 이어지고, 실패한 작업만 다시 시도할 수 있다. API 서버와 워커의 자원도 독립적으로 조정할 수 있다.
큐만 넣으면 끝나지 않는다
중복 실행을 견디게 만든다
네트워크 문제로 완료 응답이 사라지면 같은 메시지가 다시 보일 수 있다. 작업마다 멱등성 키를 두고 이미 완료된 작업인지 확인한다. 메일 발송, 결제, 외부 시스템 등록처럼 부작용이 있는 단계는 특히 중요하다.
재시도 간격을 늘린다
즉시 반복하면 장애 중인 외부 서비스에 더 큰 부하를 준다. 지수 백오프와 임의 지연을 적용하고, 재시도 가능한 오류와 입력 오류를 구분한다.
영원히 실패하는 작업을 격리한다
최대 재시도 횟수를 넘긴 작업은 실패 큐나 별도 상태로 이동한다. 오류 사유, 입력 요약, 마지막 시도 시간을 남기고 담당자가 수정 후 재실행할 수 있게 한다.
작업 가시성 시간을 맞춘다
워커가 메시지를 읽으면 일정 시간 다른 워커에서 보이지 않게 한다. 이 시간이 실제 처리 시간보다 짧으면 같은 작업이 동시에 실행될 수 있고, 너무 길면 워커 장애 후 재시작이 늦어진다.
Supabase Queues는 Postgres 기반의 내구성 있는 메시지 큐로, 가시성 시간 동안 소비자 한 곳에 메시지를 전달하고 명시적으로 삭제하거나 보관할 때까지 메시지를 유지한다. 기존 Supabase 환경에서 작은 작업 큐를 시작할 때 선택지가 될 수 있다. Supabase Queues
워커는 어디에 둘까
작업이 간헐적이고 짧다면 예약 함수나 이벤트 기반 함수로 충분할 수 있다. 계속 큐를 확인해야 하거나 처리 시간이 길고 외부 프로그램을 실행한다면 소형 상시 컨테이너가 단순하다. Render Background Worker처럼 큐를 계속 폴링하는 전용 서비스나 Railway, Fly.io, VPS의 컨테이너를 검토할 수 있다. Render Background Worker
선택 기준은 다음과 같다.
- 항상 켜져 있어야 하는가?
- 한 작업의 최대 시간과 메모리는 얼마인가?
- 동시에 몇 개를 처리해야 하는가?
- 특정 바이너리나 GPU가 필요한가?
- 장애 시 다른 인스턴스가 이어받아야 하는가?
화면에 보여줄 상태
접수됨, 대기 중, 처리 중, 완료, 실패, 취소 요청, 취소됨을 구분한다. 결과가 아직 확정되지 않았는데 완료라고 표시하지 않는다. 실패 화면에는 재시도 가능 여부와 사용자가 할 일을 구체적으로 적는다.
취소도 상태 전이다. 워커가 안전한 중단 지점에서 취소 요청을 확인하고, 이미 만들어진 임시 파일이나 부분 결과를 정리해야 한다. 외부 서비스 호출이 이미 끝났다면 되돌릴 수 있는지 별도 보상 작업을 정의한다.
운영할 때 볼 지표
- 대기 작업 수와 가장 오래된 작업의 나이
- 작업 종류별 처리 시간
- 성공률과 재시도 횟수
- 실패 큐의 증가 속도
- 워커 CPU, 메모리, 재시작 횟수
- 사용자 취소 후 실제 중단까지 걸린 시간
오래 걸리는 작업을 API 밖으로 빼는 목적은 단순히 타임아웃을 피하는 데 있지 않다. 실패, 재시도, 취소, 진행률을 업무 상태로 드러내고 복구 가능한 흐름으로 만드는 데 있다.
함께 읽기
- Worker는 제품이 아니다: Vercel·Supabase·QStash로 이해하는 비동기 처리서버리스 프로젝트에 비동기 처리를 추가하려고 하면 서비스 구성이 갑자기 복잡해 보인다. Vercel, Supabase, Upstash까지 연결했는데 Worker라는 이름이 하나 더 등장하기 때문이다.
- 사내 시스템 공개 전 확인해야 할 운영 체크리스트 30가지사내 시스템은 외부 고객 서비스보다 사용자가 적다는 이유로 공개 전 점검이 짧아지기 쉽다. 하지만 결재, 계약, 인사, 회계처럼 업무의 기준이 되는 시스템은 한 번의 권한 오류나 데이터 손실도 실제 업무 중단으로 이어진다.
- 듀오랩스가 사내 시스템을 설계하고 운영하는 7가지 원칙사내 시스템의 좋은 아키텍처는 가장 큰 서버나 가장 복잡한 기술 조합이 아니다. 현재 업무를 무리 없이 지원하고, 문제가 생겼을 때 되돌릴 수 있으며, 사용자가 늘면 필요한 부분만 확장할 수 있는 구조다.
- 월 10달러 VPS가 정말 더 저렴할까? 숨은 운영 비용 계산하기월 10달러 안팎의 VPS를 보면 Vercel, Supabase 같은 관리형 서비스를 합친 것보다 훨씬 저렴해 보인다. 실제로 안정적인 부하가 있고 서버를 운영할 사람이 있다면 VPS가 경제적일 수 있다. 하지만 인스턴스 가격만 비교하면 백업, 저장 공간, 전송량, 보안 패치, 장애 대응 시간이 빠진다.
- 클라우드 비용 폭탄을 막는 예산과 사용량 알림 설정클라우드 비용은 서버 한 대의 월정액처럼 움직이지 않는다. 트래픽, 함수 실행 시간, DB 용량, 로그, 파일 전송, 실시간 연결이 각각 늘어난다. 작은 코드 실수나 공개된 API 키 하나가 짧은 시간에 사용량을 키울 수도 있다.