백그라운드 작업과 작업 스케줄러란?

업데이트: 2026년 10월

백그라운드 작업은 앱이 큐에 넣고 워커가 실행하며 실패하면 재시도하는, 요청 주기 밖에서 실행되는 작업입니다. 경계선은 시간입니다. 응답은 즉각적으로 느껴져야 하고(수백 밀리초) 게이트웨이 타임아웃(보통 약 30초)보다 반드시 빨라야 합니다. 반면 실제 작업, 즉 SMTP를 통한 이메일 발송, 이미지 처리, 리포트 생성, 서드파티 API 호출은 수 초에서 수 분이 걸리고 재시도가 필요합니다. 이 경계를 넘어서는 일은 모두 큐에 넣고, 접수를 알리고, 다른 곳에서 처리합니다. 규모가 커지면 이것은 단순한 연결 작업이 아니라 핵심 인프라입니다. 한 대형 메시징 기업은 바로 이 메커니즘으로 하루 10억 건이 넘는 작업을 처리합니다.

핵심 요약

질문답변
아키텍처생산자가 큐에 넣음 → 큐가 저장 → 워커가 실행하고 ack
경계선응답 예산 약 300ms. 느리거나 재시도가 필요한 것은 작업으로 분리
세 가지 스케줄즉시 · 지연(“24시간 후”) · 반복(cron)
안정성 계약최소 한 번 실행 + 멱등한 작업 + 지터를 더한 백오프 + 데드 레터
조용한 실패예약 작업이 실행되지 않아도 오류는 없음 – 부재를 모니터링해야 함

모든 것을 가르쳐 주는 안티패턴

// ✗ 메일 서버에 스스로를 인질로 잡힌 가입 처리
app.post('/signup', async (req, res) => {
  const user = await createUser(req.body);
  await sendWelcomeEmail(user);        // SMTP가 느리면? 사용자는 스피너만 바라봅니다.
  res.json(user);                      // SMTP가 다운되면? 가입은 500 오류인데
});                                    // 계정은 버젓이 존재합니다. 최악의 조합입니다.

// ✔ 큐에 넣고 응답하기
app.post('/signup', async (req, res) => {
  const user = await createUser(req.body);
  await jobs.enqueue('welcomeEmail', { userId: user.id }); // 밀리초 단위
  res.json(user);                      // 이메일은 자기 일정대로 발송되고 재시도되어
});                                    // 결국 성공합니다. 사용자 눈에 띄지 않게.

실제 백엔드의 양쪽에서 본 같은 원칙입니다. 데이터를 대상으로 하는 작업과, 기다리는 대신 큐에 넣는 클라이언트입니다:

// JavaScript — Cloud Code (cloud/main.js)
// A background job: heavy work outside the request cycle
Parse.Cloud.job('sendWeeklyDigest', async (request) => {
  const query = new Parse.Query(Parse.User).equalTo('digestOptIn', true);
  await query.eachBatch(async (users) => {
    for (const user of users) await sendDigest(user); // per-record, resumable
  }, { useMasterKey: true });
  request.message('Digest run complete'); // status visible in the dashboard
});
// Run on demand or on a schedule from the dashboard — no queue to operate

생산자, 큐, 워커

재시도와 데드 레터를 갖춘 생산자, 큐, 워커 아키텍처애플리케이션은 작업을 영속적인 큐에 넣고 사용자에게 즉시 응답합니다. 워커는 작업을 가져와 실행하고 성공하면 확인 응답을 보냅니다. 실패한 작업은 지수 백오프에 따라 다시 큐에 들어가고, 재시도를 모두 소진한 작업은 점검과 재실행을 위해 데드 레터 큐로 옮겨집니다.

성공

실패

시도 횟수 소진

앱 (생산자)
큐에 넣고 빠르게 응답

큐
영속적, 대체로 순서 유지

스케줄러
cron: 정해진 시각에 다시 큐에 넣음

워커
가져오기 · 실행 · ack

완료

백오프 + 지터
지연 후 다시 큐에 넣음

데드 레터 큐
점검 · 알림 · 재실행

애플리케이션은 작업을 영속적인 큐에 넣고 사용자에게 즉시 응답합니다. 워커는 작업을 가져와 실행하고 성공하면 확인 응답을 보냅니다. 실패한 작업은 지수 백오프에 따라 다시 큐에 들어가고, 재시도를 모두 소진한 작업은 점검과 재실행을 위해 데드 레터 큐로 옮겨집니다.

세 가지 역할, 하나의 계약입니다. 생산자(producer)는 보통 요청 핸들러이며, 유형 이름과 작은 페이로드로 이루어진 작업을 만듭니다. 큐는 작업을 저장합니다. 핵심은 영속성입니다. 죽어 가는 프로세스의 메모리에만 있는 작업은 프로세스와 함께 사라지기 때문입니다. 워커는 작업을 가져와 실행하고 확인 응답을 보냅니다. 작업은 ack된 뒤에야 사라지며, 덕분에 워커가 중간에 죽어도 그 작업은 살아남아 다시 실행됩니다. 함께 따라오는 용어로는 enqueue/dequeue, ack, 가시성 타임아웃(visibility timeout)이 있습니다. 그리고 엄격히 구분해야 할 차이가 있습니다. 메시지 큐는 서비스 사이에서 데이터를 옮기며 여러 구독자에게 팬아웃될 수 있습니다. 작업 큐는 일을 실행하며, 작업 하나당 워커 하나가 정확히 한 번 맡고, 재시도와 상태가 기본으로 들어 있습니다.

세 가지 스케줄과 cron 입문

모든 작업 시스템은 같은 세 가지 시간 모드를 구현합니다. 즉시(지금 큐에 넣고 워커가 비는 대로 실행), 지연(지금 큐에 넣되 미래의 시점에 실행 가능. 리마인더, 체험 기간 만료, 그리고 재시도 메커니즘 자체), 반복(스케줄러가 달력에 따라 다시 큐에 넣음)입니다. 반복 스케줄은 거의 언제나 cron의 다섯 필드로 작성합니다:

┌ 분 (0-59)  ┌ 시 (0-23)  ┌ 일  ┌ 월  ┌ 요일
0 2 * * *      → 매일 02:00
*/15 * * * *   → 15분마다
0 9 * * 1      → 매주 월요일 09:00

스케줄러의 지뢰 두 가지: DST 전환(02:30이 사라지거나 두 번 발생하므로
UTC로 예약해야 합니다)과 실행 겹침(간격보다 오래 걸리는 실행에는 락이
필요하며, 없으면 두 사본이 같은 데이터를 처리합니다).

작업 큐 vs. 메시지 큐 vs. 스케줄러

Criterion작업 큐메시지 큐스케줄러
단위실행할 작업전달할 메시지실행할 시각
소비자정확히 하나의 워커하나 또는 여러 구독자스케줄러가 큐에 넣는 작업
기본 기능재시도, 상태, 우선순위, 지연영속성, 라우팅, 팬아웃달력, 반복
오픈소스 예Sidekiq, Celery, BullMQRabbitMQ, Kafka, Rediscron, Quartz
조합 시 역할이벤트가 요구하는 일을 실행시스템 사이를 운반정해진 시각에 큐를 채움

대부분의 “어느 것을 써야 하나?” 논쟁에 대한 답은 조합입니다. 스케줄러는 언제를 정하고, 큐는 무엇을 보관하고, 워커는 실행을 맡습니다. 야간 배치란 cron이 작업을 큐에 넣고 워커가 재시도 기능을 온전히 갖춘 채로 실행하는 것입니다.

안정성 계약

이 요소들은 보통 따로따로 소개되지만 사실은 하나의 계약입니다. 큐는 최소 한 번 실행을 약속합니다. 작업을 마친 뒤 ack 전에 워커가 죽으면 작업은 다시 실행됩니다. 이는 허술함이 아니라 피할 수 없는 일입니다. 그 대가로 여러분은 멱등성을 약속합니다. 작업 ID로 중복을 제거하고, 고유 제약 조건으로 막고, upsert로 써서 두 번째 실행이 두 번째 청구서가 아니라 아무 효과 없는 작업이 되게 합니다. 지수 백오프와 지터를 더한 재시도가 일시적인 실패를 넘기게 해 줍니다. 1초, 2초, 4초 간격에 무작위성을 더해 함께 실패한 작업 1,000개가 함께 재시도하지 않게 하는 것으로, 여러분이 이 배려를 하지 않으면 속도 제한이 있는 서드파티가 강제할 것입니다. 나머지는 데드 레터 큐가 받아 냅니다. 시도 상한에 도달한 작업은 사람이 점검하고, 고치고, 재실행할 수 있는 곳에 보관됩니다. 영구적으로 잘못된 형식의 작업은 무의미한 재시도를 아예 건너뛰고 곧바로 그곳으로 보내야 합니다.

작업을 잘 설계하는 법

작업 큐 프레임워크들이 동의하는 규칙을 모으면 다음과 같습니다. 객체가 아니라 ID를 넘깁니다. userId: "u-8fk2"를 담은 페이로드는 실행 시점에 최신 상태를 다시 가져오지만, 직렬화된 사용자 객체는 큐에 들어가는 순간부터 낡은 데이터입니다. 페이로드는 작고 단순한 JSON으로 유지하며, 시크릿은 절대 넣지 않습니다. 레코드 하나에 작업 하나를 둡니다. 사용자별 작업이 실패하면 사용자 한 명만 재시도하지만, 거대한 작업 하나가 실패하면 모든 사용자를 재시도합니다. 긴 작업은 재개 가능하게 만듭니다. 청크로 나누고, 진행 상황을 체크포인트로 남기고, 청크 처리 중 종료 신호를 받으면 깔끔하게 끝냅니다. 동시성을 가정합니다. 언젠가는 워커 두 개가 같은 행을 건드리는 인접한 작업을 동시에 처리하게 되며, 이는 설계 시점에 답하거나 장애 상황에서 답하게 되는 락 문제입니다.

큐 감시하기

백그라운드 실패는 조용합니다. 다이제스트 작업이 죽어도 오류 페이지를 보는 사용자는 없습니다. 오류 페이지를 대신하는 네 가지 지표가 있습니다. 큐 깊이(쌓이는 백로그는 워커가 밀리고 있다는 뜻입니다), 큐에 들어간 시점부터 완료까지 측정한 작업 경과 시간(40분 기다린 뒤 200ms 만에 처리된 작업은 사용자에게는 40분짜리 작업입니다), 데드 레터 큐에 알림을 건 실패율과 데드 레터 비율(누군가 잊어버린 보관 작업은 조용히 처리되지 않는 데이터이기 때문입니다), 그리고 예약 작업의 놓친 실행입니다. 마지막 것이 유독 교묘합니다. 한 번도 실행되지 않은 스케줄은 오류도, 로그 한 줄도, 작업 자체도 만들지 않았기 때문입니다. 부재에 알림을 걸어야 합니다.

일반적인 사용 사례

  • 이메일과 알림 – 지연 처리의 대표 사례입니다. 가입 시 큐에 넣고, 재시도와 함께 전달합니다.
  • 미디어 처리 – 리사이즈, 트랜스코딩, 썸네일. 어떤 요청도 기다려서는 안 되는 수 분 분량의 CPU 작업입니다.
  • 리포트와 내보내기 – 백그라운드에서 생성하고, 파일이 준비되면 알립니다.
  • 서드파티 동기화 – CRM 동기화와 웹훅 전달. 불안정한 원격 시스템에 대비해 백오프를 적용합니다.
  • 정리와 유지보수 – 야간 cron으로 실행하는 TTL 정리, 고아 데이터 제거, 다이제스트 생성.

어떤 패턴이 필요할까? 결정 매트릭스

작업의 형태선택
사용자 행동으로 트리거되고 볼륨이 변동함작업 큐 + 워커
고정된 달력, 범위가 정해져 있고 예측 가능함예약 작업(cron)
많은 레코드를 대상으로 하는 야간 배치cron이 큐에 넣고, 워커가 레코드별로 실행
서비스끼리 서로 무언가를 알림메시지 큐 / pub-sub
지금 요청 핸들러 안에 있는 느린 작업위의 리팩터링 – 큐에 넣고 응답
장애에서 살아남고 안전하게 재시도해야 함위의 어느 것이든 – 안정성 계약과 함께

한계와 트레이드오프

  • 즉시가 아니라 최종적으로 처리됩니다. 큐에 넣은 작업은 나중에 일어납니다. UI에는 대기 상태가 필요하고, “나중”에는 누군가 의도적으로 정한 한도가 필요합니다.
  • 상태가 대역 밖으로 이동합니다. 결과는 상태 필드, 콜백, 알림으로 도착합니다. 요청-응답의 단순함은 이미 써 버렸으니 연결 작업에 들 비용을 예산에 넣어야 합니다.
  • 인프라는 실재합니다. 브로커, 워커, 스케줄러는 저마다 장애 모드를 가진 서비스입니다. 아니면 플랫폼의 문제가 되며, 이것이 관리형 작업을 쓰는 근거입니다.
  • 중복은 언젠가 반드시 일어납니다. 최소 한 번이 계약입니다. 멱등하지 않은 작업은 모두 언젠가 터질 시한폭탄입니다.
  • 큐는 과부하를 우아하게, 지나치게 우아하게 숨깁니다. 늘어나는 백로그는 작업 경과 시간이 폭증하기 직전까지 평온해 보입니다. 깊이와 경과 시간 알림이 실상을 드러내는 장치입니다.

Back4app에서의 백그라운드 작업

Back4app은 관리형 데이터베이스, 자동 생성되는 REST 및 GraphQL API, 인증, 파일 스토리지, Cloud Code 서버리스 함수를 결합한 오픈소스 Backend as a Service(BaaS) 플랫폼입니다. 이곳의 작업은 스케줄이 붙은 Cloud Code입니다. Parse.Cloud.job을 정의하고(코드 탭은 eachBatch로 사용자를 배치 처리하는, 레코드별이며 재개 가능한 다이제스트 작업을 보여 줍니다) 대시보드에서 필요할 때 또는 cron 방식의 반복 주기로 실행하면, 상태와 로그는 Jobs 패널에 남습니다. 프로비저닝할 브로커도, 확장할 워커 집단도, 살려 두어야 할 큐 서비스도 없습니다. 이벤트 기반의 나머지 절반은 같은 기본 요소로 조합합니다. 요청 핸들러가 status: "queued"인 행을 쓰고, afterSave 트리거가 작업을 시작하며, 클라이언트는 폴링 대신 Live Query로 진행 상황을 지켜봅니다. 생산자/워커 패턴을 데이터로 표현한 것이며, 안정성 계약(페이로드에는 ID, 멱등한 핸들러, 알림을 걸 수 있는 상태)은 인프라가 아니라 여러분의 설계 원칙으로 남습니다.

자주 묻는 질문

백그라운드 작업이란 무엇입니까?

애플리케이션이 요청-응답 주기 밖에서 실행하는 작업입니다. 서버는 작업을 큐에 넣고 사용자에게 즉시 응답하며, 별도의 워커가 이를 비동기로 실행하고 실패하면 재시도합니다. 느리거나, 재시도가 필요하거나, 응답에 필요하지 않은 일은 모두 여기에 속합니다.

그냥 요청 핸들러에서 처리하면 안 됩니까?

느린 작업은 응답을 막고, 서버 용량을 붙잡아 두고, 게이트웨이 타임아웃에 걸리기 때문입니다. 게다가 요청 도중에 작업이 실패하면 일부는 이미 처리되었는데도 사용자는 실패를 받습니다. 대표적인 예가 가입 중에 환영 이메일을 보내는 경우로, 메일 서버가 느리면 계정 생성이 끝없이 돌아가는 스피너가 됩니다.

작업 큐는 어떻게 동작합니까?

생산자와 워커 사이에 놓인 영속적인 목록입니다. 앱이 작업(유형과 작은 페이로드)을 넣으면 큐가 이를 저장하고, 워커가 가져가 실행한 뒤 확인 응답(ack)을 보냅니다. 확인 응답을 받지 못한 작업은 큐로 돌아가며, 바로 여기서 안정성이 나옵니다.

작업 큐와 메시지 큐의 차이는 무엇입니까?

목적이 다릅니다. 메시지 큐는 서비스 사이에서 데이터를 옮기며 전달 자체가 목표이고, 메시지 하나가 여러 소비자에게 팬아웃될 수 있습니다. 작업 큐는 일을 실행하며 그 위에 재시도, 예약, 우선순위, 상태를 더하고, 각 작업은 정확히 하나의 워커에게 갑니다.

크론 작업과 백그라운드 작업의 차이는 무엇입니까?

트리거가 다릅니다. cron은 "매일 밤 새벽 2시"처럼 시간 기반이고, 백그라운드 작업은 "사용자가 파일을 업로드하면"처럼 이벤트 기반입니다. 두 패턴은 조합됩니다. 흔한 설계에서는 cron이 야간 배치를 큐에 넣고, 워커가 재시도 기능을 온전히 갖춘 채로 이를 실행합니다.

작업 재시도는 어떻게 동작합니까?

실패한 작업은 지수 백오프에 따라 1초, 2초, 4초, 8초 간격으로 자동 재실행됩니다. 여기에 무작위 지터를 더해 실패한 작업 1,000개가 같은 순간에 일제히 재시도하지 않게 하고, 최대 시도 횟수로 상한을 둡니다. 백오프는 일시적인 실패를 넘기게 해 주고, 상한은 영구적인 실패가 끝없이 재시도되는 것을 막습니다.

백그라운드 작업은 왜 멱등해야 합니까?

큐는 최소 한 번(at-least-once) 실행을 약속하기 때문입니다. 워커가 작업을 마친 뒤 확인 응답을 보내기 전에 죽으면 작업은 다시 실행됩니다. 두 번 실행되어도 두 번 과금되어서는 안 됩니다. 멱등성 키, 고유 제약 조건, upsert가 중복 실행을 아무 효과 없는 작업으로 바꿉니다.

데드 레터 큐란 무엇입니까?

재시도를 모두 소진한 작업이 가는 곳입니다. 끝없이 재시도되거나 조용히 사라지는 대신, 점검, 알림, 수동 재실행을 위해 보관됩니다. 결코 성공할 수 없는 잘못된 형식의 작업은 재시도를 건너뛰고 곧바로 이곳으로 보내야 합니다.

관련 용어

비교 대상

참고 자료

백엔드를 구축할 준비가 되셨나요?

몇 분 안에 Back4app에서 프로젝트를 시작하세요. 데이터베이스, 인증, API, Cloud Code가 포함되어 있으며 신용카드는 필요 없습니다.

작성 및 검수: Back4app Engineering, Back4app Engineering · 게시일 2026-10-31