ES /docs

S3 transient rate-limit (SlowDown 503)

RCA: Excon::Error::ServiceUnavailable — S3 503 on Thumbnail Upload

Overview#

What Happened#

tesla (Rails, cupixworks-api) 가 CarrierWave storage :fog (fog-aws → Excon) 로 썸네일 이미지를 static S3 버킷(cupix-tesla-static)에 PUT 업로드하던 중, S3 가 503 Service Unavailable (빈 body, Server: AmazonS3) 을 반환했다. 이는 Datadog Error Tracking 에만 존재하는 이슈로, cupixworks-excon 이라는 service 는 실제 앱이 아니라 APM 계측용 adapter 이름이다. 2024-09-28 부터 누적 86 건, 최근 발생은 2026-08-04 로 저빈도 산발 발생이다.

Quick Facts#

Field Value
exception.class Excon::Error::ServiceUnavailable
exception.message Expected(200) <=> Actual(503 Service Unavailable)
top_frame config/initializers/carrierwave.rb (fog storage) / app/uploaders/thumbnail_uploader.rb
env production-us (s3.us-west-2.amazonaws.com, host 10.1.82.144)

Affected Teams#

Team / Domain Error Count Impact
cupixworks-api (썸네일 업로드) 86 (2024-09 이후 누적) 개별 썸네일 업로드가 산발적으로 실패. 재시도/재업로드로 회복 가능, 지속적 사용자 영향 없음

Timeline#

  1. 2024-09-28 14:49 KST — 최초 발생 (Representative Error 의 S3 Date 헤더 Sat, 28 Sep 24 05:49:02 GMT 기준). PUT to /cupix-tesla-static/uploads/tmp/.../vr5ysr8nmiez_thumbnail.jpg → 503.
  2. 2024-09-28 ~ 2026-08-04 — 동일 클래스 산발 재발, 누적 86 건.
  3. 2026-08-04 12:28 KST — 최근 발생 (last_seen). Datadog 로그(error/warn/info)에는 대응 항목 없음 — Error Tracking 전용.

Error Log#

Datadog Logs

text
Expected(200) <=> Actual(503 Service Unavailable)
excon.error.response
  :body              => ""
  :headers           => {
    "Connection"       => "close"
    "Content-Length"   => "0"
    "Content-Type"     => "application/xml"
    "Date"             => "Sat, 28 Sep 24 05:49:02 GMT"
    "Server"           => "AmazonS3"
    "x-amz-request-id" => "895122F2AE146BEA"
  }
  :host              => "s3.us-west-2.amazonaws.com"
  :method            => "PUT"
  :path              => "/cupix-tesla-static/uploads/tmp/1727502542-839163656938588-0005-3492/vr5ysr8nmiez_thumbnail.jpg"
  :port              => 443
  :reason_phrase     => "Service Unavailable"
  :status            => 503
  :status_line       => "HTTP/1.1 503 Service Unavailable\r\n"

Impact#

  • Service: cupixworks-excon (APM adapter — 실제 앱은 tesla / cupixworks-api)
  • 발생 횟수: 86 (2024-09-28 이후 누적)
  • 최초 발생: 2024-09-28 14:49 KST
  • 최근 발생: 2026-08-04 12:28 KST

Root Cause Summary#

이 에러는 코드 결함이 아니라 AWS S3 의 transient 503 (Service Unavailable / SlowDown / 일시적 가용성 저하) 이다. tesla 의 CarrierWave 썸네일 업로드가 storage :fog 를 통해 fog-aws → Excon 으로 cupix-tesla-static 버킷의 uploads/tmp/ 경로에 이미지를 PUT 하는데, S3 가 빈 body 와 Server: AmazonS3 헤더를 담은 503 을 반환했다. 응답에 x-amz-request-id/x-amz-id-2 가 존재하고 body 가 비어 있으며 Content-Type: application/xml (S3 에러 문서 자리표시자) 인 것은 요청이 정상적으로 S3 엣지에 도달했으나 S3 측이 순간적으로 처리 불가 상태였음을 의미한다. 앱 로직·스키마·nil 참조 등 어떤 코드 경로에도 결함이 없으며, service 필드(cupixworks-excon)는 Datadog APM 계측 adapter 이름일 뿐 실제 앱 서비스가 아니다.

Technical Analysis#

Code Path#

  • Entry point: config/initializers/carrierwave.rb:1-11 — CarrierWave 를 fog(AWS) provider 로 설정. 모든 fog 업로드가 Excon HTTP 클라이언트를 경유한다.
config/initializers/carrierwave.rb:1-11ruby
Rails.application.config.to_prepare do
  CarrierWave.configure do |config|
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'] || Rails.application.credentials[Rails.env.to_sym][:aws][:access_key_id],
      aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'] || Rails.application.credentials[Rails.env.to_sym][:aws][:secret_access_key],
      path_style: true
    }
    config.fog_directory = $AWS[:s3][:static_bucket_name]
  end
end
  • 업로드 경로: app/uploaders/thumbnail_uploader.rb:7storage :fog 로 선언되어 썸네일이 static 버킷에 저장된다. 에러의 path (..._thumbnail.jpg, uploads/tmp/ prefix) 가 이 uploader 의 tmp store 단계와 일치한다.
app/uploaders/thumbnail_uploader.rb:1-11ruby
class ThumbnailUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  include SignedContentUploader

  DEFAULT_THUMB_SIZE = [300, 200].freeze

  storage :fog

  def store_dir
    model.thumbnail_path
  end
  • Failure point: fog-aws → Excon 이 PUT https://s3.us-west-2.amazonaws.com/cupix-tesla-static/uploads/tmp/...jpg 를 실행. Excon 은 200 을 기대(Expected(200))했으나 S3 가 503 을 반환하여 Excon::Error::ServiceUnavailable 를 raise 했다.
  • 기대 동작: S3 PUT 200 OK → 썸네일 업로드 성공.
  • 실제 동작: S3 가 순간적으로 503 반환 → Excon 이 예외 raise → 해당 업로드 요청 실패.

Log Evidence#

Datadog 로그(error/warn/info, 14일 retention) 검색 결과 대응하는 로그가 전혀 없다. 이 이슈는 Datadog Error Tracking 에만 존재한다.

사용한 쿼리와 결과:

text
service:cupixworks-excon "ServiceUnavailable"   (now-24h)  → Found 0 logs
"Excon::Error::ServiceUnavailable"              (now-14d)  → Found 0 logs
"uploads/tmp" "503"                             (now-14d)  → Found 0 logs

last_seen (2026-08-04) 근처에서 실제 현재 발생 메시지를 찾으려 했으나 로그가 존재하지 않으므로, 유일한 evidence 는 Error Tracking 의 Representative Error 응답이다. 해당 응답의 핵심 헤더:

text
"Server"           => "AmazonS3"
"Content-Length"   => "0"           # 빈 body
"Content-Type"     => "application/xml"
"x-amz-request-id" => "895122F2AE146BEA"
:status            => 503
:reason_phrase     => "Service Unavailable"

x-amz-request-id/x-amz-id-2 존재 + 빈 body + Server: AmazonS3 → 요청이 S3 엣지에 정상 도달했고 S3 측 일시적 처리 불가로 503 반환. 클라이언트/앱 측 요청 형식 오류(400 계열)나 인증 오류(403)가 아니다.

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 AWS S3 의 transient 503 (SlowDown/일시적 가용성 저하) — 재시도로 회복 가능한 인프라 이벤트 Server: AmazonS3, 빈 body, x-amz-request-id 존재, :status 503; 2024-09 이후 저빈도 산발 발생(86건) Confirmed
H2 앱 코드 버그 (잘못된 요청 형식, nil path, 인증 실패) 없음 503 (5xx, 서버측) 이며 4xx 아님; path 는 정상 (..._thumbnail.jpg); fog/Excon 설정 정상 (carrierwave.rb) Rejected
H3 특정 배포/코드 변경으로 인한 회귀 없음 first_seen 2024-09, last_seen 2026-08 로 약 2년에 걸친 산발 발생 — 특정 배포와 무관 Rejected
H4 지속적 S3 리전 장애 없음 상태 보드 조회 시 dep:s3-* active 인시던트 없음(bun run cli/incident-board.tsactive: null); 저빈도 산발이지 폭증 아님 Rejected

Fix Recommendation#

즉시 조치 (Critical)#

  • 코드 변경 불필요. 이는 AWS S3 의 transient 503 으로, 앱 로직 결함이 아니다. Error Tracking 에서 noise 로 처리(mute/ignore)하는 것이 적절하다.

단기 개선 (1주 이내)#

  • fog-aws 재시도 설정 검토 (선택): config/initializers/carrierwave.rbfog_credentials 또는 Excon connection 옵션에 idempotent 한 S3 PUT 에 대한 지수 백오프 재시도(retry_limit/retry_interval)를 추가하면 순간적 503 을 자동 흡수할 수 있다. 근거: S3 는 SlowDown/503 에 대해 재시도를 권장하며, 썸네일 PUT 은 재시도 안전하다.

장기 개선 (재발 방지)#

  • uploads/tmp/ 에 대한 S3 lifecycle 정책 적용으로 tmp 오브젝트 누적을 제한하여 버킷 부하/요청량을 관리.
  • Error Tracking 에서 Excon::Error::ServiceUnavailable + Server: AmazonS3 + :status 503 패턴을 별도 룰로 상시 mute 처리하여 반복적인 노이즈 알림을 억제.

Monitoring#

  • S3 5xx 응답률이 산발적 수준을 넘어 급증하는지 추적하여, transient noise 와 실제 리전 장애를 구분한다.

Datadog timeseries widget 쿼리 (fog/Excon 이 static 버킷에 붙는 tesla API 서비스의 에러율):

text
sum:trace.rack.request.errors{service:cupixworks-api}.as_rate()
text
sum:trace.rack.request.hits{service:cupixworks-api}.as_rate()

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial (코드 변경 없음; noise 처리 + 선택적 재시도 설정)

Noise Verdict#

noise — AWS S3 의 일시적 503 (Server: AmazonS3, 빈 body) 으로 코드 결함이 아니며 재시도로 회복 가능한 transient 인프라 이벤트다.