ES /docs

failed to generate thumbnail - error: Timed out connecting to server

RCA: failed to generate thumbnail - error: Timed out connecting to server

Overview#

What Happened#

2026-08-07 08:45 KST 경, production eu-central-1 리전의 cupixworks-worker (tesla Sidekiq) 호스트 하나(ip-10-1-80-125.eu-central-1.compute.internal)에서 pano 썸네일 생성 요청이 약 8초 사이 4건 연속 실패했다. 실패 원인은 tesla 가 thumbnail 생성 API Gateway (xntqdgslbc.execute-api.eu-central-1.amazonaws.com)로 보낸 HTTP POST 의 TCP connect timeout (Timed out connecting to server)이다. 이는 일시적 네트워크/인프라 이벤트이며, 호출 경로가 완전히 rescue 되어 사용자에게 노출되지 않았다 (썸네일이 재생성되지 않고 기존 썸네일이 유지될 뿐). 코드 결함이 아닌 transient noise 로 판정한다.

Quick Facts#

Field Value
exception.class Cupix::Errors::System (SYS20000) wrapping RestClient::Exceptions::OpenTimeout
exception.message failed to generate thumbnail - error: Timed out connecting to server
top_frame app/services/cupix/thumbnail_service.rb:59
runtime Ruby / Sidekiq worker (tesla)
deploy production-eu-central-1-20260806T1002Z0-9b66f324-cupixworks
env production, region eu-central-1

Affected Teams#

Team / Domain Error Count Impact
cupix (tenant) 5 (14d, 4 in single burst) pano 썸네일 재생성 1회 실패 → 기존 썸네일 유지, 사용자 영향 0

Timeline#

  1. 2026-07-31 21:52 KST — 동일 에러 1건 발생 (고립, 사전 징후).
  2. 2026-08-06 19:02 KST — 해당 리전 배포 (...20260806T1002Z0-9b66f324). 회귀 원인 아님 (아래 참조).
  3. 2026-08-07 08:45:35 KST — burst 시작, 4건 연속 실패 (모두 동일 호스트 ip-10-1-80-125).
  4. 2026-08-07 08:45:43 KST — 마지막 발생 (cluster last_seen). 이후 재발 없음 = 자가 소멸.

Error Log#

Datadog Logs

text
failed to generate thumbnail - error: Timed out connecting to server

Impact#

  • Service: cupixworks-worker
  • Team: cupix
  • 발생 횟수: 4 (cluster) / 5 (14d 로그 실측)
  • 최초 발생: 2026-08-07 08:45 KST
  • 최근 발생: 2026-08-07 08:45 KST

Root Cause Summary#

tesla 의 Cupix::ThumbnailService.generate_thumbnail! (thumbnail_service.rb:56)이 Cupix::HttpClient.post로 thumbnail 생성 API Gateway (https://xntqdgslbc.execute-api.eu-central-1.amazonaws.com/api/v1/thumbnails)에 POST 요청을 보내는 동안 TCP 연결 수립 자체가 timeout 되었다. RestClient 은 이를 RestClient::Exceptions::OpenTimeout 으로 raise 하며 그 default message 가 Timed out connecting to server 라는 고정 상수다. tesla 는 이를 rescue RestClient::Exception (thumbnail_service.rb:58)에서 Cupix::Errors::System SYS50000... 이 아닌 SYS20000 으로 재포장한다. 근본 원인은 특정 호스트↔API Gateway 구간의 일시적 네트워크 지연/불가용이며 (약 8초 창, 단일 호스트 한정, 이후 자가 소멸), tesla 코드 결함이 아니다. 다만 Cupix::HttpClient 의 재시도가 HTTP status code 기반([429,502,503,504])이라 status 가 없는 connect timeout 은 재시도되지 않는 resilience gap 이 존재한다 — 이는 결함이 아닌 개선 여지다.

Technical Analysis#

Code Path#

  • Entry point: app/workers/concerns/thumbnail_change_worker/pano.rb:9ThumbnailChangeWorker::Pano#perform(entity_id)Pano.find_by_identity.change_thumbnail_job 호출.
  • app/models/concerns/thumbnailable.rb:104-110change_thumbnail_jobchange_thumbnail_job! 을 호출하되 rescue StandardError → false 로 모든 예외를 흡수.
app/models/concerns/thumbnailable.rb:104-110ruby
def change_thumbnail_job
  change_thumbnail_job!
rescue StandardError
  false
else
  true
end
  • app/models/concerns/thumbnailable.rb:83-96change_thumbnail_job!Cupix::ThumbnailService.generate_thumbnail(source:, target:, size:) 호출 (pano 리소스 → S3 target .../thumbnail/panos/{id}).
  • app/services/cupix/thumbnail_service.rb:16-24generate_thumbnail (non-bang)이 generate_thumbnail! 을 호출하고 rescue Cupix::Errors::System → error 로깅 후 false 반환. 이것이 관측된 error 로그를 남기는 지점.
app/services/cupix/thumbnail_service.rb:16-24ruby
def generate_thumbnail(source: nil, target: nil, size: [300, 200])
  generate_thumbnail!(source: source, target: target, size: size)
rescue Cupix::Errors::System => e
  Cupix::Logger.error(e.reason, class: self.name, function: __method__, thumbnail_source: source, thumbnail_target: target, width: size[0], height: size[1])

  false
else
  true
end
  • Failure point: app/services/cupix/thumbnail_service.rb:56-60Cupix::HttpClient.post 가 connect timeout 으로 raise → rescue RestClient::ExceptionCupix::Errors::System SYS20000 으로 재포장.
app/services/cupix/thumbnail_service.rb:56-60ruby
Cupix::Logger.info('Thumbnail Requested', class: self.name, function: __method__, thumbnail_source: source, thumbnail_target: target, width: width, height: height)
response = Cupix::HttpClient.post(Cupix::Thumbnail.service_url, body.to_json, _header)
Cupix::Logger.info('Thumbnail Generated', class: self.name, function: __method__, thumbnail_source: source, thumbnail_target: target, width: width, height: height)
rescue RestClient::Exception => e
  raise Cupix::Errors::System.new(code: 'SYS20000', reason: "failed to generate thumbnail - error: #{e.message}")
  • lib/cupix/http_client.rb:34-46HttpClient.post 의 재시도는 e.http_codeRETRIABLE_STATUS_CODES = [429, 502, 503, 504] 에 포함될 때만 동작. connect timeout(OpenTimeout)은 HTTP 응답이 없어 e.http_code 가 nil → 조건 불만족 → 재시도 없이 즉시 re-raise.
lib/cupix/http_client.rb:34-46ruby
def self.post(url, payload, headers = {}, retries: MAX_RETRIES)
  attempt = 0
  begin
    RestClient.post(url, payload, headers)
  rescue RestClient::Exception => e
    if RETRIABLE_STATUS_CODES.include?(e.http_code) && attempt < retries
      attempt += 1
      sleep((2**(attempt - 1)) + rand(0.0..0.5))
      retry
    end
    raise
  end
end

기대 동작 vs 실제 동작: 기대 — thumbnail API Gateway 로 POST 후 200 수신, 썸네일 갱신. 실제 — TCP 연결 수립 단계에서 timeout → OpenTimeout raise → status code 없어 HttpClient 재시도 미발동 → SYS20000 으로 재포장 → generate_thumbnail/change_thumbnail_job 이 완전히 rescue → 썸네일 미갱신(기존 유지), error 로그만 발생. 사용자 영향 없음.

RestClient::Exceptions::OpenTimeout 은 rest-client 상 Net::OpenTimeout 을 래핑하며 default message 가 Timed out connecting to server 로 고정된 상수다 (sorbet rbi rest-client*.rbi:428-432). 따라서 대표 메시지는 변형이 아니라 신뢰 가능한 고정 문자열이다.

Log Evidence#

사용한 Datadog 쿼리:

text
service:cupixworks-worker "failed to generate thumbnail" "Timed out connecting to server"

14일 창 실측 5건 — 4건이 단일 burst(2026-08-07 08:45 KST), 1건은 2026-07-31 21:52 KST 고립 발생:

text
2026-08-07 08:45:43  error  failed to generate thumbnail - error: Timed out connecting to server  Cupix::ThumbnailService#generate_thumbnail
2026-08-07 08:45:39  error  failed to generate thumbnail - error: Timed out connecting to server  Cupix::ThumbnailService#generate_thumbnail
2026-08-07 08:45:35  error  failed to generate thumbnail - error: Timed out connecting to server  Cupix::ThumbnailService#generate_thumbnail
2026-08-07 08:45:35  error  failed to generate thumbnail - error: Timed out connecting to server  Cupix::ThumbnailService#generate_thumbnail
2026-07-31 12:52:18  error  failed to generate thumbnail - error: Timed out connecting to server  Cupix::ThumbnailService#generate_thumbnail

대표 로그의 raw attributes (burst 첫 건):

json
{
  "message": "failed to generate thumbnail - error: Timed out connecting to server",
  "status": "error",
  "class": "Cupix::ThumbnailService",
  "function": "generate_thumbnail",
  "tenant": "cupix",
  "environment": "production",
  "version": "production-eu-central-1-20260806T1002Z0-9b66f324-cupixworks",
  "host": "ip-10-1-80-125.eu-central-1.compute.internal",
  "thumbnail_target": {
    "bucket": "cupix-tesla-eu-static",
    "s3_bucket_region": "eu-central-1",
    "key": "8c00ff6b201fe746/thumbnail/panos/11047741"
  },
  "thumbnail_source": {
    "bucket": "cupixworks-source-eu2defghijkl-mece2",
    "s3_bucket_region": "me-central-2"
  }
}

증거 해석: 4건 burst 는 모두 동일 호스트(ip-10-1-80-125), 약 8초 창(08:45:35–08:45:43)에 집중 → 단일 워커 호스트↔eu-central-1 API Gateway 구간의 일시적 네트워크 이벤트. region:eu-central-1, tenant cupix → Cupix::Thumbnail.service_url (lib/cupix/thumbnail.rb:33-34)의 euce1 분기 https://xntqdgslbc.execute-api.eu-central-1.amazonaws.com/api/v1/thumbnails 이 대상. target 은 pano 썸네일. status-board (svc:cupixworks-worker::unknown) active/recent 모두 null.

동일 endpoint 의 별개 변형 — 500 Internal Server Error (14d 50+건) 는 downstream thumbnail Lambda 실행 실패로, 이 timeout cluster 와 다른 ET issue 이므로 cross-merge 하지 않는다:

text
2026-08-07 02:23:35  error  failed to generate thumbnail - error: 500 Internal Server Error
2026-08-07 00:13:41  error  failed to generate thumbnail - error: 500 Internal Server Error

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 thumbnail API Gateway 로의 TCP connect timeout (일시적 네트워크/인프라) 이 root cause, 코드 결함 아님 메시지 = RestClient::Exceptions::OpenTimeout 고정 default message (rest-client*.rbi:428-432); 4건 burst 가 단일 호스트 8초 창 집중; 이후 자가 소멸; region:eu-central-1 = xntqdgslbc.execute-api euce1 endpoint Confirmed
H2 2026-08-06 배포 회귀 (...20260806T1002Z0-9b66f324) burst 가 배포일 이후 발생 2026-07-31 에 이미 동일 에러 1건; timeout 은 코드가 아닌 전송 계층; thumbnail_service.rb/http_client.rb 배포 코드에 timeout 유발 변경 없음 (git log 상 마지막 변경 = TSLA-12414 2026-04) Rejected
H3 downstream thumbnail Lambda 결함 (500 과 동일 원인) 같은 endpoint 에서 500 다발 500 은 HTTP 응답을 받은 것(Lambda 도달); timeout 은 연결 수립 실패로 Lambda 도달 전 단계 → 다른 계층·다른 ET issue, cross-merge 금지 Rejected
H4 Cupix::HttpClient 재시도 미발동이 이 에러를 유발하는 버그 OpenTimeout.http_code = nil → RETRIABLE_STATUS_CODES 불포함 → 재시도 안 됨 (http_client.rb:39) 재시도가 있어도 8초간 지속된 연결 불가는 재시도로도 실패했을 가능성 높음; 재시도 부재는 결함이 아닌 resilience gap (status 없는 예외의 설계적 미포함, net/http timeout 계열과 동형) Rejected (gap, not bug)

Fix Recommendation#

즉시 조치 (Critical)#

없음. 호출 경로가 change_thumbnail_job (thumbnailable.rb:106)와 generate_thumbnail (thumbnail_service.rb:18) 이중으로 완전히 rescue 되어 사용자 영향이 0 이고, 근본 원인이 일시적 네트워크 이벤트이므로 코드 변경이 필요 없다. ET IGNORE 권장.

단기 개선 (1주 이내, 선택)#

  • lib/cupix/http_client.rb — 재시도 대상을 HTTP status code 뿐 아니라 transport-level 예외(RestClient::Exceptions::OpenTimeout, RestClient::Exceptions::ReadTimeout, RestClient::Exceptions::ConnectionError 등)로 확장하는 방향. 단, POST 는 idempotent 하지 않으므로(중복 썸네일 생성 위험) POST 경로 재시도는 신중해야 한다. thumbnail 생성은 target key 가 결정적(.../thumbnail/panos/{id})이라 재실행이 사실상 idempotent 이므로 이 경로에 한해 connect-timeout 재시도를 허용하는 방안이 안전하다.
  • app/services/cupix/thumbnail_service.rb:19 — 일시적 transport timeout 은 error 가 아닌 warn 레벨로 로깅하도록 예외 클래스별로 좁혀 alarm noise 를 줄이는 방안 (500/downstream 실패는 error 유지).

장기 개선 (재발 방지)#

  • thumbnail 생성은 이미 background worker(ThumbnailChangeWorker::Pano, retry: 1)로 처리되므로, Sidekiq 재시도 정책을 활용해 transport 실패 시 예외를 re-raise 하여 워커 재시도에 위임하는 구조를 검토 (현재는 change_thumbnail_jobrescue StandardError → false 가 예외를 삼켜 Sidekiq 재시도가 발동하지 않음).

Monitoring#

thumbnail connect-timeout 발생 추이:

text
service:cupixworks-worker status:error "failed to generate thumbnail - error: Timed out connecting to server"

thumbnail 생성 실패 전체(모든 변형) 추이:

text
service:cupixworks-worker status:error "failed to generate thumbnail"

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial (조치 불필요 / 선택적 개선만)