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#
- 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. - 2024-09-28 ~ 2026-08-04 — 동일 클래스 산발 재발, 누적 86 건.
- 2026-08-04 12:28 KST — 최근 발생 (
last_seen). Datadog 로그(error/warn/info)에는 대응 항목 없음 — Error Tracking 전용.
Error Log#
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 클라이언트를 경유한다.
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:7이storage :fog로 선언되어 썸네일이 static 버킷에 저장된다. 에러의 path (..._thumbnail.jpg,uploads/tmp/prefix) 가 이 uploader 의 tmp store 단계와 일치한다.
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
PUT200 OK → 썸네일 업로드 성공. - 실제 동작: S3 가 순간적으로 503 반환 → Excon 이 예외 raise → 해당 업로드 요청 실패.
Log Evidence#
Datadog 로그(error/warn/info, 14일 retention) 검색 결과 대응하는 로그가 전혀 없다. 이 이슈는 Datadog Error Tracking 에만 존재한다.
사용한 쿼리와 결과:
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 응답이다. 해당 응답의 핵심 헤더:
"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.ts → active: null); 저빈도 산발이지 폭증 아님 |
Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
- 코드 변경 불필요. 이는 AWS S3 의 transient 503 으로, 앱 로직 결함이 아니다. Error Tracking 에서 noise 로 처리(mute/ignore)하는 것이 적절하다.
단기 개선 (1주 이내)#
- fog-aws 재시도 설정 검토 (선택):
config/initializers/carrierwave.rb의fog_credentials또는 Excon connection 옵션에 idempotent 한 S3PUT에 대한 지수 백오프 재시도(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 서비스의 에러율):
sum:trace.rack.request.errors{service:cupixworks-api}.as_rate()
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 인프라 이벤트다.