Sidekiq 재시도: 백오프, 재시도 횟수, 유료 API 호출

Sidekiq은 기본적으로 실패한 작업을 약 20일간 25번 재시도합니다. 횟수를 제한하고, sidekiq_retry_in으로 retry-after만큼 기다리고, 같은 Idempotency-Key를 재사용하세요.

읽는 시간 5분Sume
전체 글

Sidekiq은 기본적으로 실패한 작업을 지수 백오프로 25번 재시도합니다. 매번 (retry_count ** 4) + 15초에 무작위 시간을 더한 만큼 기다리며 약 20일에 걸쳐 재시도하고, 그 뒤에는 작업을 Dead set으로 옮깁니다. API로 비용이 드는 일을 시작하는 작업이라면 sidekiq_options retry: 5로 횟수에 상한을 두고, sidekiq_retry_in으로 API의 retry-after만큼 기다리거나 재시도로 해결되지 않는 오류는 kill하고, Idempotency-Key를 작업 인수로 만드세요. 그래야 재시도가 두 번째 실행을 결제하는 대신 원래 실행을 재전송합니다.

Sidekiq 관련 내용은 Sidekiq 위키의 오류 처리, 모범 사례, 기본 개념 페이지와 Ruby의 Net::HTTP 문서에서, Sume 관련 내용은 Format 호출하기 (영문), 오류와 비용 (영문), 실행과 결과 (영문)에서 가져왔습니다. 모두 2026-09-28에 확인했습니다. Sume에는 Sidekiq용 gem이 없으며, 작업이 일반 HTTPS 호출을 한 번 보냅니다. 같은 패턴을 Python으로 구현한 글은 Celery 태스크 재시도: 유료 API 호출용 백오프와 지터입니다.

Sidekiq은 얼마나 오래 재시도하나요?

전체 공식은 (retry_count ** 4) + 15 + (rand(10) * (retry_count + 1))초이므로, 초반 재시도는 금방 이어지고 후반 재시도는 며칠 간격으로 벌어집니다. 마지막 재시도가 끝나면 작업은 Dead set으로 가며, Dead set은 작업을 최대 10,000개 또는 6개월까지 보관합니다. 거기서부터는 Web UI에서 직접 재시도하며, Web UI의 Retries 탭과 Dead 탭에 실패한 작업이 나열됩니다.

rand(10)이 5를 반환한다고 가정해 이 시간을 계산한 Sidekiq의 오류 처리 위키 기준, 2026-09-28 확인.
재시도직전 대기 시간누적 대기 시간
120초20초
54분 56초8분 24초
101시간 50분 26초4시간 22분 38초
1510시간 41분 46초1일 11시간 41분 52초
201일 12시간 13분 56초6일 12시간 40분 16초
253일 20시간 11분 56초20일 10시간 17분 0초

재시도 횟수는 어떻게 바꾸나요?

작업 클래스마다 sidekiq_options로 바꿉니다.

  • retry: 5: 다섯 번 재시도한 뒤 Dead set으로 보냅니다.
  • retry: 0: 재시도하지 않습니다. 실패한 작업은 곧바로 Dead set으로 갑니다.
  • retry: false: 작업이 실패하면 버려집니다.
  • retry_for: 48.hours(Sidekiq 7.1.3 이상): 횟수 대신 일정 기간 동안 재시도합니다.
  • sidekiq.yml의 :max_retries는 전역 최대값을 정합니다.
  • sidekiq_retries_exhausted는 작업이 Dead set으로 옮겨지기 직전에 실행됩니다. 누군가에게 알림을 보내기 좋은 곳입니다.

유료 API 호출은 어떻게 안전하게 재시도하나요?

실행할 때마다 같은 키와 본문을 보내세요. Sidekiq 모범 사례는 Sidekiq이 작업을 정확히 한 번이 아니라 최소 한 번 실행하며, 완료된 작업도 다시 실행될 수 있다고 말합니다. 인수는 작업의 JSON 해시 안에 담겨 전달되므로 인수로 만든 키는 매번 같고, Sume는 반복 요청에 두 번째 청구 대신 원래 영수증과 idempotency_hit: true를 담은 200으로 응답합니다. Sume 문서의 표현대로라면 시도마다 무작위 키를 쓸 경우 헤더는 장식에 불과해집니다. 나머지 재전송 사례는 AI 영상 API 멱등성 키에서 다룹니다.

sidekiq_retry_in은 재시도 횟수와 예외를 받습니다. 기다릴 초를 반환하거나, 작업을 Dead set으로 보내려면 :kill(Sidekiq 6.5.2 이상)을, 기본 지연을 쓰려면 nil을 반환하세요. 어느 경우인지는 Sume의 오류 봉투가 알려 줍니다. retryable은 다시 보내 성공할 수 있는지 알려 주고, 429에는 초 단위의 retry-after가 담겨 있으며, 문서는 503은 나중에 같은 키로 재시도하라고 말합니다. retryable로 표시되지 않은 그 밖의 4xx는 호출 자체를 고쳐야 한다는 뜻입니다. 아무것도 실행되지 않았고 아무것도 청구되지 않았으므로, Fatal은 다섯 번의 재시도를 거치지 않고 곧바로 Dead set으로 갑니다. Ruby의 Net::HTTP에서 res.code는 "429" 같은 문자열이고, res["retry-after"]로 헤더를 읽습니다.

require "net/http"
class StartVideoJob
  include Sidekiq::Job
  sidekiq_options retry: 5
  RateLimited = Class.new(StandardError)
  Fatal = Class.new(StandardError)
  sidekiq_retry_in do |count, exception|
    case exception
    when RateLimited then exception.message.to_i # the API's retry-after
    when Fatal then :kill # to the Dead set, no more retries
    end # nil: Sidekiq's default backoff
  end
  def perform(order_id, version = 1)
    res = Net::HTTP.post(URI("https://api.sume.com/v1/formats/acme/product-promo/runs"),
      { input: { order_id: order_id },
        communication: { webhook_url: "https://example.com/hooks/sume" } }.to_json,
      { "Authorization" => "Bearer #{ENV.fetch("SUME_API_KEY")}", "Content-Type" => "application/json",
        "Idempotency-Key" => "order-#{order_id}-promo-v#{version}" }) # same on every retry
    body = JSON.parse(res.body)
    return body["data"]["id"] if res.is_a?(Net::HTTPSuccess) # 202 new, 200 replay: store it
    raise RateLimited, res["retry-after"] if res.code == "429"
    raise body["error"]["code"] if body["error"]["retryable"] || res.code == "503"
    raise Fatal, "#{res.code} #{body["error"]["code"]}"
  end
end

작업이 끝난 뒤 영상 실행이 실패하면 어떻게 하나요?

Sidekiq 재시도로는 해결할 수 없습니다. 이전 키는 실패한 영수증에 묶여 있으므로, 그 키를 다시 쓰면 실패를 재전송할 뿐입니다. 다음 버전으로 새 작업을 큐에 넣으세요. StartVideoJob.perform_async(1042, 2)의 키는 -v2로 끝납니다. Sidekiq 스레드를 영상을 기다리는 데 붙잡아 두지도 마세요. 롱폼 영상은 만드는 데 15분에서 30분이 걸리며, 작업이 기다리기를 멈춰도 실행과 그 지출은 멈추지 않습니다. 실행이 완료되거나 실패하면 Sume가 서명된 format.run.terminal 영수증 하나를 communication.webhook_url로 POST합니다. 받는 방법은 Rails 웹훅: 컨트롤러에서 HMAC 서명 검증하기에서 다룹니다.

출처

관련 글

연동 카테고리의 다른 글

연동 글 전체 보기

작성자 Sume