ThumbnailService HTTP 500 — AWS API Gateway timeout
RCA: failed to generate thumbnail - error: 500 Internal Server Error
Error Log#
failed to generate thumbnail - error: 500 Internal Server Error
Impact#
- Service:
cupixworks-worker - 발생 횟수: 52
- 최초 발생: 2026-04-07T00:44:19.527Z
- 최근 발생: 2026-04-07T03:26:31.633Z
Root Cause Summary#
Cupix::ThumbnailService.generate_thumbnail!에서 AWS API Gateway 기반 외부 thumbnail 서비스(https://55d2ydipn2.execute-api.us-west-2.amazonaws.com/api/v1/thumbnails)에 HTTP POST 요청 시 500 응답을 수신하고 있습니다. 52건의 에러 모두 단일 호스트(ip-10-1-18-233.us-west-2.compute.internal, PID 957701)에서 발생했으며, 소스 이미지가 cross-region S3 버킷(us-west-1, us-east-1)에 위치합니다. 동일 시간대에 ap-southeast-2, ap-southeast-1 리전의 worker에서는 region-local 버킷을 사용하여 thumbnail 생성이 정상 동작하고 있어, us-west-2 리전의 thumbnail Lambda/API Gateway 서비스 자체의 일시적 장애 또는 cross-region S3 접근 시 발생하는 서비스 내부 오류가 원인으로 판단됩니다.
Technical Analysis#
Code Path#
- Entry point:
ThumbnailChangeWorker::Pano.perform(app/workers/concerns/thumbnail_change_worker/pano.rb:9) - Worker가
Pano.find_by_id로 엔티티를 찾고change_thumbnail_job을 호출합니다.
# app/workers/concerns/thumbnail_change_worker/pano.rb:9-17
def perform(entity_id = nil)
entity = ::Pano.find_by_id(entity_id)
if entity.nil?
Cupix::Logger.debug("Model not found: #{entity_id}")
else
entity.change_thumbnail_job
end
end
change_thumbnail_job은change_thumbnail_job!을 호출하고, 실패 시StandardError를 삼켜서false를 반환합니다 (app/models/concerns/thumbnailable.rb:104-110).
# app/models/concerns/thumbnailable.rb:104-110
def change_thumbnail_job
change_thumbnail_job!
rescue StandardError
false
else
true
end
change_thumbnail_job!은 source/target S3 정보를 구성한 후Cupix::ThumbnailService.generate_thumbnail을 호출합니다 (app/models/concerns/thumbnailable.rb:78-96).
# app/models/concerns/thumbnailable.rb:78-96
def change_thumbnail_job!
Cupix::Logger.info('Start Thumbnail Change', class: self.class.name, function: __method__, module: 'Thumbnailable', model: { id: id })
resource_s3_object = self.resource.object
s3_client_options = Cupix::StorageService.s3_client_options(storage_option: self.resource.storage_option)
Cupix::ThumbnailService.generate_thumbnail(
source: {
bucket: resource_s3_object.bucket_name,
key: resource_s3_object.key,
s3_bucket_region: self.resource.storage_option.s3_bucket_region,
s3_client_options: s3_client_options
},
target: {
bucket: self.fog_directory,
key: thumbnail_settings[:thumbnail_path],
s3_bucket_region: self.fog_credentials[:region]
},
size: thumb_size
)
generate_thumbnail(non-bang)은generate_thumbnail!을 호출하고,Cupix::Errors::System을 catch하여 에러를 로깅합니다 (app/services/cupix/thumbnail_service.rb:16-24).
# app/services/cupix/thumbnail_service.rb:16-24
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:
generate_thumbnail!에서RestClient.post가 500 응답을 받아RestClient::Exception이 발생합니다 (app/services/cupix/thumbnail_service.rb:56-59).
# app/services/cupix/thumbnail_service.rb:55-60
Cupix::Logger.info('Thumbnail Requested', class: self.name, function: __method__, thumbnail_source: source, thumbnail_target: target, width: width, height: height)
response = RestClient.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}")
end
- 호출 대상 URL은
Cupix::Thumbnail.service_url로 결정됩니다. production 환경의 us-west-2 리전에서는https://55d2ydipn2.execute-api.us-west-2.amazonaws.com/api/v1/thumbnails입니다 (lib/cupix/thumbnail.rb:44).
# lib/cupix/thumbnail.rb:32-45
when 'production'
case Cupix::Tesla.region_code
when 'euce1'
'https://xntqdgslbc.execute-api.eu-central-1.amazonaws.com/api/v1/thumbnails'
when 'apse2'
'https://dcttkvyqol.execute-api.ap-southeast-2.amazonaws.com/api/v1/thumbnails'
# ... other regions ...
else
'https://55d2ydipn2.execute-api.us-west-2.amazonaws.com/api/v1/thumbnails'
end
- 기대 동작:
RestClient.post가 200을 반환하고 thumbnail이 target S3에 저장됨 - 실제 동작: 외부 thumbnail 서비스가 500을 반환하여
RestClient::Exception발생
Log Evidence#
에러 로그 검색 쿼리:
service:cupixworks-worker status:error "failed to generate thumbnail"
52건 모두 동일한 패턴으로, 단일 호스트/PID에서 발생:
{
"message": "failed to generate thumbnail - error: 500 Internal Server Error",
"class": "Cupix::ThumbnailService",
"function": "generate_thumbnail",
"host": "ip-10-1-18-233.us-west-2.compute.internal",
"pid": "957701",
"thumbnail_source": {
"bucket": "cupixworks-source-dc9dcff32488-usea1",
"s3_bucket_region": "us-east-1"
},
"thumbnail_target": {
"bucket": "cupix-tesla-static",
"s3_bucket_region": "us-west-2"
},
"width": 300,
"height": 200
}
에러 발생 시간 분포 (4개 버스트):
00:44:19Z— 4건 (source: us-east-1)01:18:51Z ~ 01:44:21Z— 19건 (source: us-east-1)03:23:57Z ~ 03:26:31Z— 29건 (source: us-east-1 19건, us-west-1 10건)
소스 버킷 분포:
cupixworks-source-dc9dcff32488-usea1(us-east-1): 33건cupixworks-source-888a512bf858-uswe1(us-west-1): 19건
정상 동작 로그 검색 쿼리:
service:cupixworks-worker status:info "thumbnail"
동일 시간대에 ap-southeast-2와 ap-southeast-1 리전에서는 thumbnail 생성이 정상 완료됨:
{
"message": "Thumbnail Generated",
"class": "Cupix::ThumbnailService",
"function": "generate_thumbnail!",
"host": "ip-10-1-19-158.ap-southeast-2.compute.internal",
"thumbnail_source": {
"bucket": "cupixworks-source-a63f5f96341d-apse2",
"s3_bucket_region": "ap-southeast-2"
},
"thumbnail_target": {
"bucket": "cupix-tesla-au-static",
"s3_bucket_region": "ap-southeast-2"
}
}
주요 관찰: 성공 사례는 모두 region-local S3 버킷(source/target 동일 리전)을 사용하지만, 실패 사례는 모두 cross-region S3 소스(us-east-1, us-west-1 → us-west-2 thumbnail 서비스)를 사용합니다.
cupixworks-api에서 thumbnail 관련 에러 로그는 발견되지 않았습니다:
service:cupixworks-api "thumbnail" status:error
결과: 0건
Fix Recommendation#
즉시 조치 (Critical)#
- us-west-2 리전의 thumbnail Lambda/API Gateway 서비스(
55d2ydipn2.execute-api.us-west-2.amazonaws.com) 상태를 확인해야 합니다. CloudWatch 로그에서 해당 시간대의 500 에러 원인을 파악해야 합니다. - thumbnail 서비스가 cross-region S3 소스를 처리할 때 IAM 권한 또는 presigned URL 생성에 문제가 있는지 확인이 필요합니다.
단기 개선 (1주 이내)#
Cupix::ThumbnailService.generate_thumbnail!(app/services/cupix/thumbnail_service.rb:58-59)에서RestClient::Exception을 catch할 때 response body도 함께 로깅하도록 개선해야 합니다. 현재는e.message만 로깅하여 "500 Internal Server Error"라는 정보만 얻을 수 있어, 실제 실패 원인(Lambda timeout, S3 접근 실패, 메모리 초과 등)을 파악할 수 없습니다.e.response&.body를 추가 로깅하면 디버깅이 용이해집니다.ThumbnailChangeWorker의 retry를 1에서 3으로 늘려 일시적 장애에 대한 복원력을 높이는 것을 고려해야 합니다.
장기 개선 (재발 방지)#
- thumbnail 서비스가 cross-region S3 접근을 안정적으로 처리할 수 있도록 아키텍처를 검토해야 합니다. 현재 다른 리전(ap-southeast-2 등)에서는 region-local 버킷으로 정상 동작하므로, us-west-2 리전에서도 source가 다른 리전에 있을 때의 처리 로직을 확인해야 합니다.
- thumbnail 서비스에 circuit breaker 패턴을 도입하여, 연속 실패 시 불필요한 재시도를 방지하고 빠르게 실패를 감지할 수 있도록 해야 합니다.
Monitoring#
- thumbnail 서비스 500 에러 모니터링:
service:cupixworks-worker status:error "failed to generate thumbnail"
- 리전별 thumbnail 생성 성공/실패 비교:
service:cupixworks-worker ("Thumbnail Generated" OR "failed to generate thumbnail") @host:*us-west-2*
- thumbnail Lambda CloudWatch 에러 모니터링 추가 (AWS Console)
Risk Assessment#
- Risk level: medium
- 예상 복잡도: standard — thumbnail 서비스(Lambda/API Gateway) 측 로그 확인이 필요하며, worker 코드 자체의 수정은 에러 로깅 개선 수준으로 간단하나, 근본 원인이 외부 서비스에 있으므로 인프라 점검이 함께 필요합니다.