ES /docs

[CupixAerialMap] preprocess fail {"message":"Endpoint request timed out"}

RCA: [CupixAerialMap] preprocess fail - Endpoint request timed out

Overview#

What Happened#

2026-04-21 eu-central-1 리전에서 aerial-map-service의 preprocess 단계가 Pix4D Cloud API 호출 중 {"message":"Endpoint request timed out"} 에러로 2회 실패했다. 동일 tenant(cupix)의 동일 팀(rakentava)에서 연속으로 요청한 aerial map ID 24(oblique)와 25(nadir)가 모두 영향을 받았다.

Quick Facts#

Field Value
exception.message {"message":"Endpoint request timed out"}
top_frame src/preprocess/index.ts:148
runtime Node.js 20 on ECS Fargate (1024 CPU, 2048 MB)
deploy cupix-aerial-map-preprocess:prod (sha256:4e7e2be7a3bb)
env production, eu-central-1

Affected Teams#

Team / Domain Error Count Impact
rakentava 2 Aerial map ID 24, 25의 preprocess 실패. 사용자의 드론 사진 처리가 완료되지 않음

Timeline#

  1. 09:49:56 UTC — Aerial map 24 (oblique) navigate → preprocess 시작
  2. 09:50:58 UTC — Pix4D project 생성 완료
  3. 09:51:27 UTC — Pix4D API 호출 중 "Endpoint request timed out" 에러 발생 (첫 번째 실패)
  4. 09:52:23 UTC — preprocess-check Lambda: States.TaskFailed 확인, process-fail 처리
  5. 10:05:16 UTC — Aerial map 25 (nadir) navigate → preprocess 시작
  6. 10:06:13 UTC — Pix4D project 생성 완료
  7. 10:08:43 UTC — configProcessing 완료 (horizontal_crs: 32635)
  8. 10:09:12 UTCstartProcessing 호출 중 "Endpoint request timed out" 에러 발생 (두 번째 실패)
  9. 10:10:09 UTC — preprocess-check Lambda: States.TaskFailed 확인, process-fail 처리

Error Log#

Datadog Logs

text
[CupixAerialMap] preprocess fail {"message":"Endpoint request timed out"}

Impact#

  • Service: aerial-map-service
  • 발생 횟수: 2
  • 최초 발생: 2026-04-21T09:51:27.709Z
  • 최근 발생: 2026-04-21T10:09:12.790Z

Root Cause Summary#

Pix4D Cloud API(PIX4D_ENDPOINT)가 AWS API Gateway 뒤에서 동작하며, API Gateway의 기본 통합 타임아웃(29초) 내에 Pix4D 백엔드가 응답하지 못해 504 {"message":"Endpoint request timed out"} 에러가 반환되었다. aerial-map-service의 axios 클라이언트는 5xx 에러에 대해 최대 3회 재시도하지만, Pix4D 백엔드 자체의 지연(과부하 또는 일시적 장애)으로 인해 재시도 역시 동일하게 타임아웃되어 최종 실패하였다. 두 건의 에러는 동일 팀의 연속 요청에서 ~18분 간격으로 발생하여, Pix4D 측 일시적 서비스 저하가 원인으로 판단된다.

Technical Analysis#

Code Path#

  • Entry point: src/preprocess/index.ts:156 — CLI 입력 파싱 후 app(input) 호출
  • 실행 흐름:
    1. cupixApi.saveProcessingState() — Cupix API에 "preprocessing" 상태 저장
    2. cupixApi.getAerialPhotosByAerialMapId() — 사진 목록 조회
    3. downloadStreamByUrl() + readPhotoExif() — 첫 사진 EXIF 읽기
    4. cupixApi.saveCameraAndImageInfo() — 카메라 정보 저장
    5. pix4dApi.createPix4dProject() — Pix4D 프로젝트 생성 (로그에서 성공 확인)
    6. pix4dApi.getPix4dS3Credential() — S3 자격증명 획득
    7. 사진 다운로드/업로드 루프 (p-limit 10 동시)
    8. pix4dApi.registerPix4dImages() — 이미지 벌크 등록
    9. pix4dApi.registerGcps() — GCP 등록 (없으면 skip)
    10. cupixApi.getAerialMap() — CRS 정보 조회
    11. pix4dApi.configProcessing() — 처리 옵션 설정
    12. pix4dApi.startProcessing()처리 시작 요청 (Failure point)
src/code/src/preprocess/index.ts:144-153typescript
  } 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;
  }

error.message{"message":"Endpoint request timed out"}인 이유: Pix4D API 클래스의 catch 블록에서 throw new Error(JSON.stringify(error.response?.data || error.message))로 에러를 재생성하기 때문. API Gateway의 504 응답 body가 그대로 error message에 포함된다.

src/code/src/common/api.ts:239-256typescript
  async startProcessing(projectId: number) {
    try {
      console.log(`[CupixApi-Pix4d] startProcessing - /project/api/v3/projects/${projectId}/start_processing`);

      const response = await axios.post(
        `${this._endpoint}/project/api/v3/projects/${projectId}/start_processing`,
        {},
        { headers: { Authorization: `Bearer ${this._accessToken}` } },
      );

      return response.data;
    } catch (error: any) {
      console.error(
        `[CupixApi-Pix4d] startProcessing - /project/api/v3/projects/${projectId}/start_processing - ${error.message}`,
      );
      throw new Error(JSON.stringify(error.response?.data || error.message));
    }
  }
  • Axios 클라이언트 설정: timeout 60초, 5xx 에러 시 최대 3회 재시도 (지수 백오프: 1s, 2s, 4s)
src/code/src/common/axios.ts:3-10typescript
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,
});
  • Occurrence 1 (aerial map 24): createPix4dProject 성공 후 ~29초 뒤 실패. configProcessing 로그가 없으므로 사진 업로드 또는 registerPix4dImages 단계에서 Pix4D API 타임아웃 발생 추정
  • Occurrence 2 (aerial map 25): configProcessing 성공 후 정확히 29초 뒤 실패. startProcessing 호출에서 Pix4D API Gateway 타임아웃 발생 확정

Log Evidence#

검색 쿼리:

text
service:aerial-map-service status:error
Time range: 2026-04-21T08:50:00Z to 2026-04-21T10:40:00Z
text
service:aerial-map-service
Time range: 2026-04-21T09:40:00Z to 2026-04-21T10:20:00Z (ascending)

Occurrence 1 (aerial map 24) 로그 타임라인:

text
18:50:58 KST [CupixAerialMap] create pix4d project - project name: cupix-production-rakentava-24-1776765058394
18:51:27 KST [CupixAerialMap] preprocess fail {"message":"Endpoint request timed out"}
18:51:27 KST [CupixAerialMap] preprocess fail - error:({}) / message:({"message":"Endpoint request timed out"})

프로젝트 생성과 에러 사이 29초. configProcessing 로그가 없으므로 그 이전 Pix4D API 호출에서 실패.

Occurrence 2 (aerial map 25) 로그 타임라인:

text
19:06:13 KST [CupixAerialMap] create pix4d project - project name: cupix-production-rakentava-25-1776765973348
19:08:43 KST [CupixAerialMap] No GCPs provided, proceeding without GCP registration
19:08:43 KST [CupixAerialMap] configProcessing - horizontal_crs: 32635, vertical_crs: 3900, geoid_model: FIN2023N2000, geoid_height: null
19:09:12 KST [CupixAerialMap] preprocess fail {"message":"Endpoint request timed out"}
19:09:12 KST [CupixAerialMap] preprocess fail - error:({}) / message:({"message":"Endpoint request timed out"})

configProcessing과 에러 사이 정확히 29초 — startProcessing 호출에서 API Gateway 504 타임아웃.

ECS Task 정보 (preprocess-check Lambda에서 확인):

json
{
  "StopCode": "EssentialContainerExited",
  "StoppedReason": "Essential container in task exited",
  "ExitCode": 1,
  "StartedBy": "AWS Step Functions",
  "LaunchType": "FARGATE",
  "Cpu": "1024",
  "Memory": "2048"
}

No warn-level logsservice:aerial-map-service status:warn 검색에서 0건. Axios 재시도 warn 로그([AerialMap] Request failed ...retrying)가 없다는 것은 재시도가 발생하지 않았거나, 504 응답이 retryable 조건에 매칭되지 않았을 가능성을 시사한다. 그러나 코드상 error.response.status >= 500 체크가 있으므로 504는 재시도 대상이다. warn 로그가 Datadog에 없는 이유는 console.warn이 Datadog에서 info 레벨로 수집될 수 있기 때문이다 — uncertain, needs verification.

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 Pix4D Cloud API Gateway 타임아웃 (29초) — Pix4D 백엔드 지연 에러 메시지 {"message":"Endpoint request timed out"}는 AWS API Gateway 504 응답의 표준 포맷. occurrence 2에서 configProcessing → error 간격이 정확히 29초 Confirmed
H2 Cupix API (CUPIX_ENDPOINT) CloudFront 타임아웃 CloudFront origin_read_timeout = 60초 (infra 코드 확인). CloudFront 504 에러는 HTML 형식이지 JSON {"message":...} 형식이 아님 Cupix API는 CloudFront 뒤에 있으며 60초 타임아웃. 에러 형식이 API Gateway JSON과 일치하지 않음 Rejected
H3 Axios 클라이언트 자체 타임아웃 (60초) REQUEST_TIMEOUT_MS = 60000 설정 에러 메시지가 timeout of 60000ms exceeded가 아닌 {"message":"Endpoint request timed out"}. 간격이 60초가 아닌 29초 Rejected
H4 네트워크 연결 문제 (ECONNRESET 등) 에러 코드가 ECONNRESET/ETIMEDOUT이 아닌 504 응답 body. error:({}) — error 객체가 빈 JSON으로 serialize됨 (Error 객체의 enumerable properties가 없음) Rejected
H5 ECS Fargate 리소스 부족으로 인한 처리 지연 Fargate memory 2048MB, CPU 1024 에러가 외부 API 호출(Pix4D)에서 발생. Fargate 내부 연산이 아닌 HTTP 응답 타임아웃. 메모리 사용량도 정상 Rejected

Fix Recommendation#

즉시 조치 (Critical)#

  • 없음. Pix4D 외부 서비스의 일시적 지연이 원인이므로 aerial-map-service 코드 자체에 즉각적인 버그 수정은 불필요하다. 현재 에러 발생 시 process-fail Lambda가 정상적으로 실패 처리하고 있다.

단기 개선 (1주 이내)#

  • Pix4D API 호출 재시도 로직 강화: src/code/src/common/axios.tsMAX_RETRIES를 3에서 5로 늘리고, BASE_DELAY_MS를 더 길게 설정(예: 3000ms)하여 Pix4D 백엔드 복구 시간을 확보한다. 특히 startProcessing 같은 중요 API 호출에 대해 별도의 긴 재시도 정책을 적용하는 것을 고려한다.
  • 에러 메시지 개선: src/code/src/common/api.ts의 각 Pix4D API 메서드에서 catch 시 어떤 endpoint에서 타임아웃이 발생했는지 명확히 로깅한다. 현재는 error.message만 기록되어 어떤 API 호출이 실패했는지 로그만으로 특정하기 어렵다.
  • Pix4D API 응답 코드 로깅: axios interceptor의 warn 로그에 error.response?.status를 추가하여 재시도 발생 여부와 HTTP 상태 코드를 추적할 수 있도록 한다.

장기 개선 (재발 방지)#

  • 자동 재처리(retry) 메커니즘: Step Functions 워크플로에 preprocess 실패 시 자동 재시도 로직 추가. 현재는 실패 → process-fail로 바로 이동하지만, 일시적 타임아웃의 경우 일정 시간 후 재시도하면 성공할 가능성이 높다.
  • Pix4D API 상태 모니터링: Pix4D Cloud API의 응답 시간과 에러율을 Datadog에서 모니터링하여, Pix4D 측 성능 저하를 조기에 감지한다.

Monitoring#

  • Pix4D API 타임아웃 에러 발생 빈도 모니터링:
text
service:aerial-map-service "Endpoint request timed out" status:error
  • Pix4D API 호출 지연 시간 추적 (axios interceptor에 메트릭 추가 필요):
text
avg:aerial_map.pix4d_api.response_time{endpoint:start_processing}

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial
  • Pix4D 외부 서비스의 일시적 지연이며, 동일 팀의 연속 2건만 영향 받음. 시스템 전반에 대한 구조적 문제가 아닌 외부 의존성 타임아웃으로, aerial-map-service 코드의 재시도 강화로 완화 가능하다.