Articlestack.convex.dev·2026년 7월 7일·0

How to connect Convex to RunPod for serverless GPU workloads

Quick Summary

이 글은 Convex가 파일 업로드 직후 RunPod 서버리스 GPU 워커를 호출하고, 워커가 처리 결과를 다시 Convex Storage와 데이터베이스에 반영하는 배경 제거 워크플로를 설명한다.

How to connect Convex to RunPod for serverless GPU workloads 관련 대표 이미지

🖼️ 인포그래픽

How to connect Convex to RunPod for serverless GPU workloads 내용을 설명하는 본문 이미지

🖼️ 4컷 인포그래픽

How to connect Convex to RunPod for serverless GPU workloads 내용을 설명하는 본문 이미지

💡 한 줄 요약

이 글은 Convex가 파일 업로드 직후 RunPod 서버리스 GPU 워커를 호출하고, 워커가 처리 결과를 다시 Convex Storage와 데이터베이스에 반영하는 배경 제거 워크플로를 설명한다.

📌 핵심 요약

  • 글쓴이는 50~100MB 규모의 동영상 업로드를 다루는 프로젝트에서 원본 저장, 저해상도 변환, 처리 상태 동기화가 비용과 구조 면에서 부담이 되는 문제를 겪었다.
  • RunPod는 필요할 때만 GPU를 띄워 작업을 실행하고 종료하는 서버리스 엔드포인트를 제공하므로, 배경 제거처럼 GPU가 필요한 오픈소스 모델 실행에 적합한 선택지로 제시된다.
  • Convex는 업로드된 파일의 공개 URL을 가져오고, 작업 상태를 데이터베이스에 기록하며, RunPod API를 호출하는 액션과 내부 mutation을 통해 GPU 작업을 백엔드 흐름에 연결한다.
  • RunPod 워커는 입력 파일 URL과 작업 ID를 받아 파일을 다운로드하고, 배경 제거 로직을 실행한 뒤, Convex가 발급한 업로드 URL로 결과물을 Storage에 올리고 mutation으로 상태를 갱신한다.
  • 전체 패턴은 백엔드가 긴 GPU 작업의 API 응답을 기다리지 않고, 워커가 Convex로 직접 결과와 상태를 다시 기록하게 만들어 UI가 작업 진행과 완료를 실시간으로 반영할 수 있게 한다.

🧩 주요 포인트

  1. 글쓴이는 50~100MB 규모의 동영상 업로드를 다루는 프로젝트에서 원본 저장, 저해상도 변환, 처리 상태 동기화가 비용과 구조 면에서 부담이 되는 문제를 겪었다.
  2. RunPod는 필요할 때만 GPU를 띄워 작업을 실행하고 종료하는 서버리스 엔드포인트를 제공하므로, 배경 제거처럼 GPU가 필요한 오픈소스 모델 실행에 적합한 선택지로 제시된다.
  3. Convex는 업로드된 파일의 공개 URL을 가져오고, 작업 상태를 데이터베이스에 기록하며, RunPod API를 호출하는 액션과 내부 mutation을 통해 GPU 작업을 백엔드 흐름에 연결한다.
  4. RunPod 워커는 입력 파일 URL과 작업 ID를 받아 파일을 다운로드하고, 배경 제거 로직을 실행한 뒤, Convex가 발급한 업로드 URL로 결과물을 Storage에 올리고 mutation으로 상태를 갱신한다.
  5. 전체 패턴은 백엔드가 긴 GPU 작업의 API 응답을 기다리지 않고, 워커가 Convex로 직접 결과와 상태를 다시 기록하게 만들어 UI가 작업 진행과 완료를 실시간으로 반영할 수 있게 한다.

🧠 상세 정리

1. 문제의 출발점: 대용량 미디어 업로드와 처리 비용

글은 사용자가 동영상 파일을 업로드하는 프로젝트에서 출발한다. 각 파일이 약 50~100MB였기 때문에 원본 해상도로 저장하고 처리하면 대역폭과 스토리지 비용이 크게 늘어날 수 있었다. 글쓴이는 업로드 직후 동영상을 압축하고, 고해상도와 저해상도 버전을 모두 저장하며, 이 상태를 데이터베이스와 깔끔하게 동기화하는 방법이 필요했다. 단순히 파일을 저장하는 문제가 아니라, 업로드 이후의 후처리와 결과 관리까지 백엔드 흐름 안에 자연스럽게 넣어야 하는 상황이었다.

2. GPU가 필요한 작업과 RunPod 선택 이유

글쓴이는 동영상 압축 외에도 AI 배경 제거 같은 워크플로를 다뤄야 했다고 설명한다. 이런 작업에는 사용할 만한 저렴한 API가 없었지만, GPU에서 실행할 수 있는 오픈소스 모델은 존재했다. RunPod는 GPU 모델을 서버리스 엔드포인트로 배포할 수 있게 해 주며, GPU가 필요할 때만 켜지고 작업 후 종료되는 방식으로 사용량 기반 과금을 가능하게 한다. 따라서 항상 GPU 인스턴스를 유지하지 않고도 배경 제거 같은 무거운 AI 작업을 필요 시점에 실행할 수 있는 구조가 된다.

3. Convex와 RunPod를 결합한 전체 흐름

이 글의 핵심 구조는 Convex가 업로드 이벤트 이후 GPU 작업을 시작하고, RunPod 워커가 실제 처리를 수행한 뒤 Convex에 다시 결과를 기록하는 방식이다. 사용자가 동영상을 업로드하면 Convex action이 실행되어 RunPod 서버리스 API에 배경 제거 작업을 요청한다. RunPod 쪽에서는 동영상을 받아 배경 제거를 처리하고, 최종 파일을 Convex Storage에 직접 업로드한다. 이후 데이터베이스에 결과 파일 ID와 상태를 저장하므로, 백엔드는 긴 GPU 작업의 완료를 기다리며 막히지 않는다.

4. 프로젝트 구성: Convex, Next.js, Convex Auth

예제 프로젝트는 Convex와 Next.js, Convex Auth를 기반으로 구성된다. 글쓴이는 npm create convex@latest로 새 프로젝트를 만들고, Convex CLI가 프론트엔드 프레임워크와 인증 방식을 선택해 필요한 보일러플레이트를 생성한다고 설명한다. 이후 기본 placeholder UI를 실제 앱 형태로 바꾸기 위해 Cursor에 파일 업로더, Convex Storage 저장, 업로드 파일 목록 표시, masonry grid 형태의 갤러리 구현을 요청했다. 애플리케이션은 npx convex dev로 실행되며, 먼저 일반적인 파일 업로드 웹사이트가 정상 동작하는 상태를 만든 뒤 배경 제거 기능을 추가한다.

5. 작업 상태 추적을 위한 removeBgJobs 테이블

배경 제거 기능을 붙이기 전, 글은 removeBgJobs 테이블을 schema에 추가하라고 안내한다. 이 테이블은 원본 파일을 가리키는 fileId, 작업 상태를 나타내는 status, 처리 결과를 가리키는 resultId를 저장한다. 상태 값은 pending, processing, completed, failed 중 하나로 정의되며, 처리 단계에 따라 업데이트된다. 이 구조 덕분에 하나의 업로드 파일이 배경 제거 작업의 어떤 단계에 있는지 추적할 수 있고, 완료 후에는 원본과 처리 결과를 데이터베이스 레벨에서 연결할 수 있다.

6. Convex 내부 mutation과 RunPod 호출 action

Convex 쪽 첫 번째 핵심 함수는 updateRemoveBgInternal 내부 mutation이다. 이 함수는 removeBgJobId를 받아 해당 작업의 상태나 결과 파일 ID를 patch하며, 클라이언트에 직접 노출하기보다 action 같은 신뢰된 서버 측 코드에서 호출되도록 설계된다. 두 번째 함수인 startRemoveBgWorker action은 업로드된 동영상의 URL을 Convex Storage에서 가져오고, 작업 상태를 pending으로 바꾼 뒤 RunPod API의 /run 엔드포인트를 호출한다. 요청 본문에는 Convex의 작업 ID와 파일 URL이 들어가며, 응답에서는 RunPod 작업 ID를 반환한다.

7. 외부 워커가 Convex에 기록하기 위한 mutation

RunPod 워커가 처리 진행 상황과 결과를 Convex에 반영하려면 외부에서 호출 가능한 mutation이 필요하다. 글은 workerUpdateRemoveBg mutation을 정의해 워커가 작업 상태를 processing이나 completed로 바꾸고, 결과 파일의 Storage ID를 저장할 수 있게 한다. 또한 workerGenerateUploadUrl mutation은 Convex Storage에 파일을 업로드할 수 있는 보안 업로드 URL을 생성한다. 이 방식은 외부 GPU 워커가 데이터베이스 접근 권한 전체를 갖지 않고도, 제한된 함수 호출과 임시 업로드 URL을 통해 처리 결과를 Convex에 반영하게 만든다.

8. Python RunPod 핸들러의 처리 순서

RunPod 워커는 Python으로 작성되며 requests, runpod, convex 패키지를 사용한다. 핸들러는 이벤트 입력에서 remove_bg_job_idfile_url을 읽고, 먼저 Convex mutation을 호출해 상태를 processing으로 갱신한다. 그다음 입력 미디어를 다운로드하고, 실제 배경 제거 로직을 실행한 뒤, Convex에서 업로드 URL을 받아 처리된 결과 파일을 Storage에 업로드한다. 마지막으로 결과 Storage ID와 함께 상태를 completed로 업데이트하고, 응답으로 storageIdcompleted 상태를 반환한다.

9. 실시간 상태 반영과 비동기 GPU 워크플로의 의미

이 구조의 장점은 GPU 작업이 백엔드의 일반 요청 흐름을 오래 붙잡지 않는다는 점이다. Convex action은 RunPod 작업을 시작하고 필요한 식별자를 넘기는 역할을 하며, 실제 배경 제거와 업로드는 RunPod 워커가 별도로 수행한다. 워커가 Convex mutation을 호출해 상태를 갱신하므로, 해당 작업을 구독하는 UI는 진행 상태와 완료 결과를 자동으로 반영할 수 있다. 글의 설명에 따르면 이 패턴은 배경 제거에 한정되지 않고, Convex가 GPU 작업을 오케스트레이션하고 워커가 결과를 되돌려 쓰는 일반적인 서버리스 GPU 처리 방식으로 활용될 수 있다.

🧾 핵심 주장 / 시사점

  • 핵심 설계 포인트는 Convex가 GPU 작업을 직접 처리하지 않고, 작업 시작과 상태 저장을 맡으며 RunPod 워커가 무거운 연산과 결과 업로드를 담당하도록 역할을 나눈 것이다.
  • Convex Storage의 업로드 URL 생성과 worker mutation 조합은 외부 GPU 워커가 처리 결과를 안전하게 되돌려 쓰는 실용적인 연결 방식으로 제시된다.
  • 긴 배경 제거 작업을 API 응답 대기 방식으로 처리하지 않고 상태 기반 비동기 흐름으로 분리하면, 사용자 인터페이스는 진행 상황을 반영하면서도 백엔드 요청은 막히지 않는다.

✅ 액션 아이템

  • Convex 업로드 직후 공개 URL 수집, 상태 저장, RunPod API 호출을 하나의 연동 흐름으로 묶어 긴 작업에서도 데이터 정합성을 확보한다.
  • RunPod 워커는 입력 파일 URL과 작업 ID로 배경 제거를 수행한 뒤 Convex 업로드 URL에 결과를 올리고 mutation으로 처리 상태를 갱신한다.
  • 백엔드는 GPU 작업의 API 응답을 기다리지 않게 하고, 워커가 직접 결과·상태를 재기록해 UI에 진행과 완료 표시를 실시간 반영한다.

❓ 열린 질문

  • 50~100MB 업로드 처리에서 원본 보존·저해상도 변환 부담을 고려한 분산 실행 임계값은 어디에서 정해야 하는가?
  • 필요 시 GPU를 띄우는 RunPod 호출이 실패하거나 과부하될 때 재시도 정책은 Convex 상태 기록과 어떻게 맞물려야 하는가?
  • 배경 제거 워크플로에서 worker가 직접 상태를 갱신할 때 완료·오류 판정의 기준은 무엇이며 어떻게 모호함을 줄일 것인가?

관련 문서

공통 태그와 주제 흐름을 기준으로 같이 보면 좋은 문서를 이어서 제안합니다.