ES /docs

TransferManager::uploadFile | response path: /tmp/workspace/675912/alignments_all.json, code: 503, m

RCA: TransferManager::uploadFile | S3 503 Slow Down

Error Log#

Datadog Logs

text
TransferManager::uploadFile | response path: /tmp/workspace/675912/alignments_all.json, code: 503, message: Slow Down

Impact#

  • Service: cupixworks-capture-postprocessor-agent
  • Team: southlandind
  • 발생 횟수: 1 (이 클러스터), 7+ (최근 1주간 동일 패턴)
  • 최초 발생: 2026-04-06T21:41:03.045Z
  • 최근 발생: 2026-04-06T21:41:03.045Z

Root Cause Summary#

AWS S3가 요청 속도 제한(rate limiting)으로 인해 HTTP 503 "Slow Down" 응답을 반환했으며, TransferManager::uploadFile은 이 응답을 받으면 즉시 에러로 처리하고 reject한다. uploadFile이 직접 호출될 때(task queue를 거치지 않고 PostprocessorService::uploadAlignmentData에서 직접 await하는 경우)에는 retryTask 로직이 적용되지 않아 재시도 없이 실패한다. 이후 uploadAlignmentDatacatch 블록이 이 에러를 warn 레벨로만 로깅하고 삼켜버려, alignment 데이터 업로드가 조용히 누락된다. 최근 1주간 여러 리전(us-east-1, us-west-1, us-west-2)에서 동일한 S3 503 Slow Down 패턴이 반복 발생하고 있어, 이는 일시적 S3 스로틀링이 아니라 구조적인 재시도 미비 문제이다.

Technical Analysis#

Code Path#

  • Entry point: postprocessor-service.ts:105await this.uploadAlignmentData(cpCapture) 호출
  • uploadAlignmentData는 Tesla API에서 presigned URL을 받아 transferManager.uploadFile()을 직접 await로 호출한다 (postprocessor-service.ts:202).
  • uploadFile (transfer.manager.ts:81-107) 내부에서 request.put()으로 S3에 PUT 요청을 보낸다.
  • S3가 503 응답을 반환하면, sendReq.on('response') 핸들러(transfer.manager.ts:93-101)에서 statusCode !== 200이므로 reject()된다.
  • uploadAlignmentDatacatch 블록(postprocessor-service.ts:214-216)이 에러를 warn으로 로깅하고 종료 — 재시도 없음, 에러 전파 없음.

핵심 문제 1 — 직접 호출 시 재시도 없음:

uploadFile이 task queue가 아닌 직접 호출로 사용될 때, retryTask 메커니즘이 적용되지 않는다. task queue의 transferTaskretryTask 경로(transfer.manager.ts:193-214)만 retry를 지원한다.

typescript
// postprocessor-service.ts:201-206 — 직접 호출, retry 없음
if (allResultsResource && allResultsResource.upload_url) {
	await this.transferManager.uploadFile(
		allResultsResource.upload_url,
		allResultsFilePath,
		{}
	);
typescript
// transfer.manager.ts:81-107 — 503 시 즉시 reject
uploadFile = (url: string, path: string, headers: any): Promise<void> => new Promise((resolve, reject) => {
	// ...
	sendReq
		.on('response', async res => {
			if (res.statusCode === 200) {
				// ...
				resolve();
			} else {
				logger.error('TransferManager::uploadFile | response path: %s, code: %d, message: %s', path, res.statusCode, res.statusMessage);
				reject(this.cupixAuth.handleError(res));
			}
		})

핵심 문제 2 — 에러를 삼키는 catch 블록:

typescript
// postprocessor-service.ts:214-216 — 에러를 warn으로만 기록하고 삼킴
} catch (error) {
	logger.warn('PostprocessorService::uploadAlignmentData | end - %s', JSON.stringify(error));
}

기대 동작: S3 503은 일시적 스로틀링이므로 exponential backoff로 재시도 후 업로드 완료되어야 한다. 실제 동작: 재시도 없이 즉시 실패하고, alignment 데이터 업로드가 누락된다.

핵심 문제 3 — checkStatusCode 로직의 범위 오류:

typescript
// transfer.manager.ts:168-171
private checkStatusCode = (error: any): boolean => {
	if (error?.statusCode != undefined && error.statusCode > 400 && error.statusCode < 500) return false;
	return true;
};

이 메서드는 400-499(4xx) 에러만 재시도 불가로 판단한다. 503은 이 범위 밖이므로 retry 대상이지만, task queue 경로에서만 retryTask가 호출되므로 직접 호출 시에는 의미가 없다.

Log Evidence#

사용한 Datadog 쿼리:

text
service:cupixworks-capture-postprocessor-agent status:error "TransferManager"
Time range: 2026-04-06T20:00:00Z to 2026-04-06T23:00:00Z
text
service:cupixworks-capture-postprocessor-agent "503" OR "Slow Down"
Time range: 2026-04-01T00:00:00Z to 2026-04-07T00:00:00Z

이벤트 타임라인 (workspace 675912):

Timestamp (KST) Level Message
2026-04-07 06:41:03 error TransferManager::uploadFile | response path: /tmp/workspace/675912/alignments_all.json, code: 503, message: Slow Down
2026-04-07 06:41:03 warn CupixAuth::handleError | Undefined response: {"statusCode":503,"request":{"method":"PUT"}}
2026-04-07 06:41:03 warn PostprocessorService::uploadAlignmentData | end - {"statusCode":503,...,"server":"AmazonS3"}
2026-04-07 06:41:12 info BaseService::cleanUpAnythingRelatedModel | path: /tmp/workspace/675912
2026-04-07 06:41:13 info BaseService::cleanUpAnythingRelatedModel | path: /tmp/workspace/675912

에러 발생 후 ~9초 만에 workspace cleanup이 진행되었다. 이는 uploadAlignmentData가 에러를 삼킨 후 후속 작업이 정상 진행된 것을 의미한다.

S3 응답 상세 (원문):

json
{
  "statusCode": 503,
  "headers": {
    "x-amz-request-id": "8ACMRBQWQ6J4XDDD",
    "server": "AmazonS3"
  },
  "request": {
    "uri": {
      "hostname": "s3.amazonaws.com",
      "pathname": "/cupixworks-source-dc9dcff32488-usea1/resources/6yllrt/usea1/v1"
    },
    "method": "PUT",
    "headers": {
      "Content-Length": 4092175,
      "content-type": "application/json"
    }
  }
}

최근 1주 동일 패턴 (7건 이상 확인):

Date (KST) Workspace File Region Size
2026-04-07 06:41 675912 alignments_all.json us-east-1 4MB
2026-04-04 07:35 675109 process_output.zip us-west-2 124MB
2026-04-04 05:44 675124 process_output.zip us-west-1 23MB
2026-04-04 04:06 674892 process_output.zip us-east-1 174MB
2026-04-03 08:32 673435 process_output.zip us-west-1 147MB
2026-04-02 08:40 674059 process_output.zip us-west-2 56MB
2026-04-02 05:41 673932 process_output.zip us-east-1 150MB

여러 리전과 버킷에서 발생하므로, 단일 버킷 이슈가 아닌 요청 패턴에 의한 S3 스로틀링이다.

Fix Recommendation#

즉시 조치 (Critical)#

  • postprocessor-service.ts:167-217: uploadAlignmentData에서 this.transferManager.uploadFile() 직접 호출 대신 exponential backoff가 포함된 retry wrapper를 적용해야 한다. S3 503은 일시적이므로 3-5회 재시도(1s, 2s, 4s 간격)면 대부분 해결된다.
  • postprocessor-service.ts:214-216: catch 블록이 에러를 삼키지 않고 상위로 전파하거나, 최소한 retry 실패 후에만 warn으로 로깅하도록 변경해야 한다. 현재는 alignment 데이터 누락이 무시되어 데이터 정합성 문제가 발생할 수 있다.

단기 개선 (1주 이내)#

  • uploadFile 메서드(transfer.manager.ts:81-107) 자체에 5xx 응답에 대한 retry 로직을 내장해야 한다. 현재 task queue 경로에서만 retry가 동작하는 이중 구조는 직접 호출 시 취약점이 된다.
  • 동일한 패턴이 uploadProcessOutput(postprocessor-service.ts:250-274)에서도 발생하고 있으므로 함께 수정해야 한다 (로그 증거: 최근 1주간 process_output.zip 업로드 실패 다수).

장기 개선 (재발 방지)#

  • S3 업로드를 AWS SDK v3의 @aws-sdk/lib-storage로 마이그레이션하면 multipart upload + 내장 retry + exponential backoff를 모두 지원한다. 현재 request 라이브러리(deprecated) 기반의 직접 PUT은 대용량 파일(100MB+) 업로드에 비효율적이며 스로틀링에 취약하다.
  • 모든 직접 uploadFile 호출 지점을 task queue 경로로 통일하여 retry 로직의 일관성을 확보해야 한다.

Monitoring#

  • S3 503 발생 빈도 추적:
text
service:cupixworks-capture-postprocessor-agent status:error "code: 503"
  • alignment 데이터 업로드 실패 추적:
text
service:cupixworks-capture-postprocessor-agent status:warn "uploadAlignmentData"
  • S3 요청 메트릭 (CloudWatch):
text
aws.s3.5xx_errors{bucket:cupixworks-source-*}

Risk Assessment#

  • Risk level: medium
  • 예상 복잡도: standard — retry wrapper 추가는 비교적 단순하지만, 모든 직접 호출 지점을 파악하고 일관되게 적용해야 한다. alignment 데이터 누락이 downstream 처리에 미치는 영향은 추가 확인이 필요하다.