PanoPostprocessorService::run | resize pano id:82157654 | error {"stack":"HttpError: HTTP request fa
RCA: PanoPostprocessorService resize pano HttpError 502
Overview#
What Happened#
2026-04-23 11:13:54 UTC에 cupixworks-pano-postprocessor-instance 서비스에서 pano id:82157654의 resize 처리 중 cupixworks-api로의 checkTileUploading API 호출이 HTTP 502 에러로 실패했다. 이는 AWS S3의 일시적인 InternalError로 인해 API 서버가 S3 list_objects_v2 호출에 실패하면서 발생한 것이며, 해당 시간대(11:10~11:14 UTC)에 S3 관련 에러가 집중적으로 발생했다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | HttpError |
| exception.message | HTTP request failed |
| top_frame | panoApi.js:545 |
| env | production, us-west-2 |
Timeline#
- 11:10:33Z~11:10:45Z — S3
InternalError로 인해AwsS3Manager::downloadParallel에서 15건 이상의 다운로드 실패 발생 - 11:10:58Z —
MaskWork::maskPanos에러 (cv2 assertion failed), 이전 처리 실패 - 11:11:09Z — S3 업로드 503 (Service Unavailable) 에러 발생
- 11:11:34Z~11:13:54Z —
cupixworks-api에서 pano 82157654check_tile_uploading6회 연속 502 응답 (Aws::S3::Errors::InternalError) - 11:13:54.212Z — 본 클러스터 에러: postprocessor가
checkTileUploading호출 시 502 수신 - 11:13:55Z — pano 82157654에 대한 후속 API 호출 200 성공 (S3 복구)
- 11:13:56Z — postprocessor
terminateService호출, 강제 종료
Error Log#
PanoPostprocessorService::run | resize pano id:82157654 | error {"stack":"HttpError: HTTP request failed
at Request._callback (/tmp/agent/dist/node_modules/@tesla/typescript-node-sdk/api/panoApi.js:545:40)
at self.callback (/tmp/agent/dist/node_modules/request/request.js:185:22)
at Request.emit (node:events:524:28)
at Request.emit (node:domain:489:12)
at Request.<anonymous> (/tmp/agent/dist/node_modules/request/request.js:1154:10)
at Request.emit (node:events:524:28)
at Request.emit (node:domain:489:12)
at IncomingMessage.<anonymous> (/tmp/agent/dist/node_modules/request/request.js:1076:12)
at Object.onceWrapper (node:events:638:28)
at IncomingMessage.emit (node:events:536:35)","message":"HTTP request failed","response":{"body":{},"statusCode":502},"body":{},"statusCode":502,"name":"HttpError"}
Impact#
- Service:
cupixworks-pano-postprocessor-instance - Team: gad
- 발생 횟수: 1
- 최초 발생: 2026-04-23T11:13:54.212Z
- 최근 발생: 2026-04-23T11:13:54.212Z
pano id:82157654의 resize 처리가 실패했으며, 해당 pano의 상태가 Error로 전환되었다. 단일 pano에 대한 영향이며 전체 capture 작업은 run | end로 종료되었다.
Root Cause Summary#
AWS S3의 일시적인 InternalError가 근본 원인이다. postprocessor의 resize 단계에서 ResizeWork::uploadResizedImage가 resized 이미지를 S3에 업로드한 후 cupixworks-api의 PUT /api/v1/panos/82157654/check_tile_uploading 엔드포인트를 호출한다. 이 API는 내부적으로 Cupix::StorageService.object_list를 통해 S3 list_objects_v2를 실행하여 업로드된 타일 객체를 확인하는데, 해당 시점에 S3가 InternalError를 반환하면서 API가 502를 응답했다. postprocessor 측에서는 이 502 에러에 대한 재시도 로직이 없어 즉시 실패 처리되었다.
Technical Analysis#
Code Path#
- Entry point:
pano-postprocessor-service.ts:79—run()메서드 시작 - Resize 단계 시작:
pano-postprocessor-service.ts:164-179—cpPanos.map으로 각 pano에 대해 병렬 resize 작업 실행 - 개별 pano 처리:
pano-postprocessor-service.ts:168-170—resizePano→uploadResizedImage→checkStitched순차 실행
// resize
start = Date.now();
const resizeTasks = cpPanos.map((cpPano) => {
return PARALLEL_TASK_LIMIT(async () => {
try {
await this.resizeWork.resizePano(cpPano);
await this.resizeWork.uploadResizedImage(cpPano);
await this.resizeWork.checkStitched(cpPano);
} catch (error) {
logger.error('PanoPostprocessorService::run | resize pano id:%d | error %s', cpPano.panoId, stringifyError(error));
await this.panoPostprocessorManager.updatePanoState(cpPano.panoId!, TESLA.UpdatePanoRequest.StateEnum.Error);
erroredPanoIds.add(cpPano.panoId!);
}
});
});
- Failure point:
resize-work.ts:142—checkTileUploadingAPI 호출에서 502 수신
uploadResizedImage = async (cpPano: CPPano): Promise<void> => {
if (!cpPano.panoId) return;
const credentials = await this.cupixApi.pano.createTileUploadCredentials(cpPano.panoId);
await this.awsS3Manager.uploadDirectoryByCredential({ credential: credentials, directory: cpPano.resizeDir!});
await this.cupixApi.pano.checkTileUploading(cpPano.panoId);
};
- API 측 호출 체인:
pano.api.ts:79-83→@tesla/typescript-node-sdk→PUT /api/v1/panos/:id/check_tile_uploading
async checkTileUploading(panoId: number, revisionType?: 'enhanced_image'): Promise<TESLA.Pano> {
const api = await this.api();
const res = await api.checkTileUploading(panoId, Fields.PanoFields, revisionType as any);
return unwrapAttributes(res);
}
- Rails API 처리:
tilable_repository/pano.rb:18→tile/s3.rb:9-13— S3list_objects_v2호출
def check_tile_uploading!
self.tile_size = tile_uploading_objects.size if self.has_attribute?(:tile_size)
raise Cupix::Errors::InvalidState.new(code: 'STAT10000', reason: 'No tile objects found in S3') if tile_size.nil? || tile_size.zero?
self.uploaded_tile_state!
end
def tile_uploading_objects
Cupix::StorageService.object_list(
storage_option: storage_option,
bucket_name: storage_option.s3_hosting_bucket_name,
prefix: tile_object_key_base(ver: tile_upload_revision)
)
end
def object_list(storage_option: nil, **kwargs)
opts = parse_storage_option(storage_option).merge(kwargs)
check_required_params(opts, %i[region bucket_name prefix])
client(storage_option: storage_option)
.list_objects_v2(
bucket: storage_option.s3_hosting_bucket_name,
prefix: opts[:prefix],
delimiter: 'delimiter'
)
.contents
.reject do |object|
object.key.end_with?('/')
end
end
실패 흐름 요약: list_objects_v2에서 Aws::S3::Errors::InternalError 발생 → Rails가 500/502 응답 → @tesla/typescript-node-sdk의 panoApi.js:545에서 HttpError throw → postprocessor catch 블록에서 pano 상태를 Error로 업데이트
Log Evidence#
postprocessor 서비스 에러 로그 검색:
service:cupixworks-pano-postprocessor-instance status:error @environment:production
대상 에러 (11:13:54.212Z):
PanoPostprocessorService::run | resize pano id:82157654 | error {"stack":"HttpError: HTTP request failed...","statusCode":502}
S3 다운로드 InternalError (11:10:33Z~11:10:45Z):
AwsS3Manager::downloadParallel | begin - "We encountered an internal error. Please try again."
15건 이상 반복 발생 — AWS S3 자체의 일시적 장애 확인.
S3 업로드 503 (11:11:09Z):
AwsS3Manager::uploadDirectoryByCredential | upload failed — S3 returned 503 (Service Unavailable)
downstream API (cupixworks-api) 로그 검색:
service:cupixworks-api 82157654
API 측 502 응답 6회 연속 (11:11:34Z~11:13:54Z):
[502] PUT /api/v1/panos/82157654/check_tile_uploading — Aws::S3::Errors::InternalError
| Timestamp | Status | Endpoint |
|---|---|---|
| 11:11:34.798Z | 502 | PUT /api/v1/panos/82157654/check_tile_uploading |
| 11:12:00.823Z | 502 | PUT /api/v1/panos/82157654/check_tile_uploading |
| 11:12:26.856Z | 502 | PUT /api/v1/panos/82157654/check_tile_uploading |
| 11:12:54.511Z | 502 | PUT /api/v1/panos/82157654/check_tile_uploading |
| 11:13:24.572Z | 502 | PUT /api/v1/panos/82157654/check_tile_uploading |
| 11:13:54.627Z | 502 | PUT /api/v1/panos/82157654/check_tile_uploading |
S3 복구 확인 (11:13:55Z):
[200] PUT /api/v1/panos/82157654 — (정상 업데이트)
에러 발생 1초 후 동일 pano에 대한 API 호출이 정상 응답 — S3 장애가 일시적이었음을 확인.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | AWS S3 일시적 InternalError로 인해 API가 502를 반환하고 postprocessor가 실패 | API 로그에서 Aws::S3::Errors::InternalError로 6회 연속 502 확인; S3 다운로드/업로드에서도 동시간대 InternalError/503 다수 발생; 1초 후 정상 복구 |
— | Confirmed |
| H2 | postprocessor의 resized 이미지 업로드 실패로 S3에 타일 객체가 없어 check_tile_uploading!이 InvalidState 에러 발생 |
업로드 단계(uploadDirectoryByCredential)가 checkTileUploading 이전에 실행됨 |
에러 메시지가 InvalidState가 아닌 HttpError 502이며, API 로그에서 명확히 Aws::S3::Errors::InternalError 확인 — S3 리스트 자체가 실패한 것이지 객체 부재가 아님 |
Rejected |
| H3 | API 서버 자체의 과부하 또는 배포 문제로 502 발생 | 같은 시간대에 다른 504/400 에러도 존재 (08:20-08:37 UTC) | API 서버가 아닌 S3가 에러 원인임이 로그에서 확인됨; 다른 pano에 대한 API 호출은 정상 동작; 1초 후 즉시 복구 | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
resize-work.ts:142:checkTileUploading호출에 재시도 로직 추가. 502/503/504 등 서버 에러 응답 시 exponential backoff으로 최대 3회 재시도하도록 변경. 현재는 S3 일시 장애 시 즉시 실패하여 pano 상태가Error로 전환된다.- 동일하게
uploadResizedImage전체 메서드에 대해 재시도 래핑 적용 검토 필요.
단기 개선 (1주 이내)#
pano-postprocessor-service.ts:164-179의 resize 단계에서 개별 pano 실패 시 재시도 후에도 실패하면erroredPanoIds에 추가하되, 일시적 에러(502/503)와 영구적 에러(400/404)를 구분하여 로깅 레벨을 조정. 일시적 에러는warn레벨이 적절할 수 있다.@agents/api패키지 또는@tesla/typescript-node-sdk수준에서 공통 HTTP 재시도 미들웨어 도입 검토. 현재 SDK(request기반)에는 재시도 기능이 없다.
장기 개선 (재발 방지)#
- Rails API(
tile/s3.rb:16-22)의tile_uploading_objects에서Aws::S3::Errors::InternalError를 catch하여 재시도 후 실패 시 명확한 에러 코드와 메시지를 반환하도록 개선. 현재는 S3 에러가 unhandled exception으로 502가 되어 클라이언트가 원인을 파악하기 어렵다. request라이브러리 의존 제거 및axios등 재시도 지원 HTTP 클라이언트로 마이그레이션 검토.
Monitoring#
- S3 관련 에러 빈도 모니터링:
service:cupixworks-api "Aws::S3::Errors::InternalError" status:error
- postprocessor resize 단계 실패율 모니터링:
service:cupixworks-pano-postprocessor-instance "resize pano" status:error
- S3 InternalError가 특정 시간대에 집중되는 패턴이 있는지 일별 추이 확인.
Risk Assessment#
- Risk level: low
- 예상 복잡도: standard
- AWS S3 InternalError는 일시적이며 자동 복구되는 인프라 이슈. 재시도 로직 추가로 대부분의 재발을 방지할 수 있다. 발생 빈도가 1회이며 1초 후 정상 복구된 점에서 시스템적 위험은 낮다.