CloudFront origin connection failure — 504 Gateway Timeout
RCA: [CupixAerialMap] preprocess fail - CloudFront 504 Gateway Timeout
Overview#
What Happened#
2026-04-23 15:28~16:04 KST 사이에 aerial-map-service의 preprocess 및 postprocess Fargate 태스크가 Cupix API 호출 시 CloudFront로부터 504 Gateway Timeout 응답을 받아 실패했다. 이 클러스터는 preprocess fail 1건을 포함하며, 같은 시간대에 postprocess fail도 6건 발생했다 (별도 fingerprint).
Quick Facts#
| Field | Value |
|---|---|
| exception.message | 504 Gateway Timeout ERROR - Generated by cloudfront (CloudFront) HTTP3 Server |
| top_frame | src/preprocess/index.ts:175 |
| runtime | Node.js 20 on ECS Fargate (2048 MB) |
| env | production, us-west-2 |
Timeline#
- 2026-04-23 15:28:21 KST — 최초 postprocess 504 에러 발생 (aerial map ID 불확인)
- 2026-04-23 15:49:57 KST — aerial map 334의 preprocess 성공 (정상 요청 확인)
- 2026-04-23 15:51:19 KST — aerial map 334의 preprocess fail (504 Gateway Timeout) - 이 클러스터의 대표 에러
- 2026-04-23 15:52:17 KST — preprocess-check Lambda가 Fargate 태스크 실패 감지 (ExitCode: 1, aerial map 332)
- 2026-04-23 15:58:34~16:04:47 KST — postprocess에서도 동일 504 에러 반복 발생
- 2026-04-23 16:02:05 KST — aerial map 333의 postprocess-check 성공 (정상 요청 확인)
Error Log#
[CupixAerialMap] preprocess fail - error:({}) / message:("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>504 Gateway Timeout ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront) HTTP3 Server
Request ID: PMhS5RtFCDBDI0Vx1w78L2K-1ODzBQZ_wtx8tVSjyH8L5pXekuyhMA==
</PRE>
</BODY></HTML>")
Impact#
- Service:
aerial-map-service - 발생 횟수: 1 (이 클러스터, preprocess fail), 동일 시간대 postprocess fail 6건 추가 발생
- 최초 발생: 2026-04-23T06:51:20.076Z
- 최근 발생: 2026-04-23T06:51:20.076Z
Root Cause Summary#
aerial-map-service의 Fargate 태스크(preprocess/postprocess)가 Cupix API(CUPIX_ENDPOINT)에 HTTP 요청을 보낼 때, 해당 API 앞단의 CloudFront distribution이 origin 서버에 연결하지 못해 504 Gateway Timeout을 반환했다. 이 HTML 에러 응답이 axios에 의해 Error 객체로 변환되어 catch 블록에서 error.message로 로깅되었다. 504는 서버 에러이므로 axios retry interceptor가 3회 재시도를 수행했으나, CloudFront origin 장애가 지속되어 모든 재시도가 실패했다. 이는 aerial-map-service 코드 결함이 아니라, CloudFront-origin 간 일시적 연결 장애 (인프라 이슈)로 인한 transient failure이다.
Technical Analysis#
Code Path#
- Entry point:
src/preprocess/index.ts:168— IIFE에서app(input)호출 app()함수 내부에서CupixApi인스턴스 생성 후 여러 API 호출 수행 (src/preprocess/index.ts:39-45)- CupixApi의 모든 HTTP 요청은 커스텀 axios 인스턴스를 사용 (
src/common/axios.ts:8-10) - Failure point:
src/preprocess/index.ts:175— catch 블록에서 에러 로깅
(async () => {
try {
await app(input);
logger.info(`[CupixAerialMap] preprocess success`);
await sleep(30000); // sleep for log push
process.exit(0);
} catch (error: any) {
logger.error(`[CupixAerialMap] preprocess fail - error:(${JSON.stringify(error)}) / message:(${error.message})`);
await sleep(30000); // sleep for log push
process.exit(1);
}
})();
app() 내부에서 cupixApi.saveProcessingState() 등 API 호출 시 CloudFront 504를 수신하면, axios가 error.response.data에 HTML 응답을 담아 에러를 throw한다. 에러가 AerialMapError 인스턴스가 아니므로 else 분기로 진입하여 AMB710 (Preprocess Fail) 코드로 저장된다.
} catch (error: any) {
if (error instanceof AerialMapError) {
await cupixApi.saveError(aerialMapId, error.code, error.reason);
} else {
logger.error(`[CupixAerialMap] preprocess fail ${error.message}`);
await cupixApi.saveError(aerialMapId, ERROR_CODE['AMB710'].code, ERROR_CODE['AMB710'].reason);
}
throw error;
}
axios retry interceptor는 500번대 에러에 대해 최대 3회 재시도를 수행하나, CloudFront 장애가 지속되어 모든 재시도가 실패했다:
const RETRY_CODES = ['ECONNRESET', 'ETIMEDOUT', 'ECONNABORTED', 'EAI_AGAIN'];
const MAX_RETRIES = 3;
const BASE_DELAY_MS = 1000;
const REQUEST_TIMEOUT_MS = 60000;
const axios = _axios.create({
timeout: REQUEST_TIMEOUT_MS,
});
axios.interceptors.response.use(undefined, async (error) => {
const config = error.config;
if (!config) throw error;
config.__retryCount = config.__retryCount || 0;
const retryable = RETRY_CODES.includes(error.code) || (error.response?.status && error.response.status >= 500);
if (!retryable || config.__retryCount >= MAX_RETRIES) {
throw error;
}
// ... exponential backoff retry
});
error.response.status >= 500 조건에 504가 포함되어 retry가 트리거되었으나, 총 재시도 시간(1s + 2s + 4s = ~7초)으로는 CloudFront origin 장애 회복에 충분하지 않았다.
Log Evidence#
사용한 Datadog 쿼리:
service:aerial-map-service status:error
service:aerial-map-service "preprocess"
service:aerial-map-service status:error "504 Gateway Timeout"
15:49:57 KST에 aerial map 334가 정상 preprocess 완료 후, 15:51:19 KST에 같은 aerial map의 후속 요청 시 504가 발생했다:
[2026-04-23 15:49:57 KST] [info] [CupixAerialMap] preprocess success
[2026-04-23 15:49:57 KST] [info] [CupixAerialMap] preprocess time: 45277ms
[2026-04-23 15:51:19 KST] [error] [CupixAerialMap] preprocess fail "<!DOCTYPE HTML...504 Gateway Timeout ERROR..."
[2026-04-23 15:51:20 KST] [error] [CupixAerialMap] preprocess fail - error:({}) / message:("...504 Gateway Timeout...")
preprocess-check Lambda가 Fargate 태스크 실패를 감지한 로그 (aerial map 332, ExitCode 1):
[2026-04-23 15:52:17 KST] [info] [CupixAerialMap] preprocess-check - event({"Error":"States.TaskFailed","Cause":"...ExitCode\":1...StopCode\":\"EssentialContainerExited\"..."})
동시간대 정상 처리된 요청도 존재 — aerial map 333이 16:02에 성공적으로 postprocess 완료:
[2026-04-23 16:02:05 KST] [info] postprocess-check - event({"result":"success","aerialMap":{"id":333,...}})
[2026-04-23 16:02:08 KST] [info] cupix-process-success-production-vdco - pix4d process finish: success
cupixworks-api 서비스에서 동시간대 aerial_map 관련 에러는 0건 — API 서버 자체의 에러가 아닌 CloudFront 레이어의 문제임을 확인:
service:cupixworks-api status:error "aerial_map" — 0 results (2026-04-23 06:20~07:10 UTC)
3일간(04/2004/23) 504 Gateway Timeout 에러 검색 결과, 모든 5건이 2026-04-23 15:2816:04 KST에 집중되어 있어 일시적 burst 패턴을 보인다.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | CloudFront-origin 간 일시적 연결 장애로 504 발생 | 에러 메시지가 CloudFront가 생성한 504 HTML 페이지; 같은 시간대 preprocess/postprocess 모두 동일 패턴; API 서버 자체 에러 0건; 일부 요청은 같은 시간대에 성공 | — | Confirmed |
| H2 | Cupix API 서버 과부하/다운으로 인한 에러 | 504는 origin 연결 실패 시 발생 가능 | cupixworks-api 서비스에 동시간대 에러 로그 0건; aerial map 333이 16:02에 정상 처리됨; 504가 API 서버가 아닌 CloudFront에서 생성됨 | Rejected |
| H3 | aerial-map-service의 axios timeout(60초) 초과 | REQUEST_TIMEOUT_MS=60000 설정 있음 | 에러 메시지가 ETIMEDOUT이 아닌 CloudFront HTML 504 응답; axios timeout과 CloudFront 504는 다른 에러 패턴 | Rejected |
| H4 | Pix4D API 호출 실패 | Pix4dApi도 같은 axios 인스턴스 사용 | 에러 메시지에 Pix4D 관련 내용 없음; CloudFront는 Cupix API 앞단에 위치; Pix4D API는 별도 endpoint 사용 | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
- 조치 불필요: 이 에러는 CloudFront 인프라의 일시적 장애로 인한 transient failure이다. aerial-map-service 코드 결함이 아니므로 코드 수정 대상이 아니다.
단기 개선 (1주 이내)#
src/common/axios.ts:5—MAX_RETRIES를 3에서 5로 증가하고,BASE_DELAY_MS에 jitter를 추가하여 CloudFront 장애 시 회복 가능성을 높인다.src/preprocess/index.ts:175및src/postprocess/index.ts:179—JSON.stringify(error)가{}를 출력하는 문제가 있다. Error 객체는 JSON.stringify에서 빈 객체가 되므로,error.response?.status,error.response?.data등 유용한 정보를 별도로 로깅하도록 변경해야 한다.
장기 개선 (재발 방지)#
- CloudFront origin failover 설정을 검토하여 primary origin 장애 시 secondary origin으로 자동 전환되도록 구성한다.
- aerial-map-service에서 Cupix API 호출 실패 시 Step Functions 레벨에서 재시도하는 retry policy를 추가한다. 현재는 Fargate 태스크가 ExitCode 1로 종료되면 즉시 실패로 처리된다.
Monitoring#
- CloudFront 504 에러율 모니터링 추가:
service:aerial-map-service status:error "504 Gateway Timeout"
- Cupix API origin의 health check 및 latency 메트릭을 CloudWatch에서 모니터링
- aerial-map-service의 preprocess/postprocess 실패율 추적:
service:aerial-map-service status:error ("preprocess fail" OR "postprocess fail")
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial — CloudFront 인프라의 transient failure로, 코드 수정 없이도 자연 해소됨. 로깅 개선과 retry 강화는 선택적 개선 사항.