S3 HEAD latency spike unprotected by timeout/retry
RCA: Api::V1::PointcloudsController#check_octree_uploading Latency (1064ms)
Overview#
What Happened#
2026-05-26 23:39 UTC에 cupixworks-api 서비스의 check_octree_uploading 엔드포인트에서 1064ms의 응답 지연이 발생했다. 이 엔드포인트는 octree 파일 업로드 완료 여부를 확인하기 위해 AWS S3 HEAD 요청을 동기적으로 수행하며, S3 응답 지연이 전체 API 응답 시간에 직접 반영되는 구조이다.
Quick Facts#
| Field | Value |
|---|---|
| resource_name | Api::V1::PointcloudsController#check_octree_uploading |
| top_frame | app/models/concerns/octree.rb:9 |
| env | production, us-west-2 |
| avg_duration | 1064ms |
| cluster_type | latency |
Timeline#
- 2026-05-26T23:39:23Z — check_octree_uploading 요청에서 1064ms 지연 감지 (APM trace ID: 3703117997578681932)
- 2026-05-27 — Error sweeper 자동 수집 및 RCA 분석
Error Log#
{
"resource_name": "Api::V1::PointcloudsController#check_octree_uploading",
"service": "cupixworks-api",
"occurrences": 1,
"avg_ms": 1064,
"max_ms": 1064,
"sample_trace_id": "3703117997578681932"
}
Impact#
- Service:
cupixworks-api - 발생 횟수: 1
- 최초 발생: 2026-05-26T23:39:23.662Z
- 최근 발생: 2026-05-26T23:39:23.662Z
- 영향: Octree 업로드 확인 API 호출 시 1초 이상 지연. 클라이언트가 업로드 완료 후 상태 전환을 확인하는 동안 사용자 경험 저하 가능.
Root Cause Summary#
check_octree_uploading 엔드포인트는 octree 파일의 업로드 완료 여부를 확인하기 위해 Aws::S3::Object#exists? (S3 HEAD 요청)를 매번 동기적으로 호출한다. S3 HEAD 요청은 네트워크 왕복 시간에 의존하며, 캐싱이나 타임아웃 제어 없이 직접 호출되고 있다. APM 메트릭에 따르면 이 엔드포인트의 평균 응답 시간은 300-450ms이며, 피크 시 700ms 이상에 도달한다. 1064ms는 S3 서비스 지연이 일시적으로 증가했을 때의 상위 백분위수 outlier로 판단된다.
Technical Analysis#
Code Path#
- Entry point:
app/controllers/concerns/octree_controller.rb:4 - Repository:
app/repositories/concerns/octree_repository.rb:4 - Model method:
app/models/concerns/octree.rb:26 - Failure point (latency source):
app/models/concerns/octree.rb:9
def check_octree_uploading
repository_instance.check_octree_uploading
render_api Renderable.new({
contents: @model
})
end
def check_octree_uploading
case @model.octree_state_name
when :uploading
raise Cupix::Errors::Resource.new(code: 'RESC10000', reason: 'Octree does not uploaded') unless @model.check_octree_uploading
else
raise Cupix::Errors::InvalidState.new(code: 'STAT10000', reason: "Invalid state: #{@model.octree_state}")
end
@model
end
def octree_uploaded?
octree_object.exists? # AWS S3 HEAD request - primary latency source
end
def octree_object
Cupix::StorageService.object(
storage_option: storage_option,
bucket_name: storage_option.s3_hosting_bucket_name,
key: self.octree_object_key
)
end
def object(storage_option: nil, **kwargs)
opts = parse_storage_option(storage_option).merge(kwargs)
opts[:force_path_style] = true
check_required_params(opts, %i[region bucket_name key])
Aws::S3::Object.new(opts)
end
실행 흐름:
- Controller → Repository에서
octree_state_name이:uploading인지 확인 - Model의
check_octree_uploading→octree_uploaded?호출 octree_uploaded?는octree_object.exists?를 호출 — 이것이 AWS S3 HEAD 요청storage_option조회 시Rails.cache사용 (1주 TTL,storagable.rb:87), 그러나 S3 HEAD 결과는 캐싱 없음- S3 HEAD 요청의 네트워크 왕복 시간이 전체 응답 지연의 주요 원인
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-api "check_octree_uploading"
Time: 2026-05-26T22:30:00Z to 2026-05-27T00:30:00Z
로그에서 확인된 패턴 — 모든 요청이 200 OK로 응답:
{
"timestamp": "2026-05-27 09:18:13 KST",
"status": "info",
"message": "[200] PUT /api/v1/pointclouds/117124/check_octree_uploading (Api::V1::PointcloudsController#check_octree_uploading)"
}
APM 메트릭 (최근 1시간, avg:trace.rack.request.duration):
Query: avg:trace.rack.request.duration{service:cupixworks-api,resource_name:api::v1::pointcloudscontroller_check_octree_uploading}
Results: 47 data points
- Min: 0.199s (199ms)
- Max: 0.783s (783ms)
- Avg: ~0.42s (420ms)
- Peak period: 0.7-0.78s at timestamps 1779838680000-1779838920000
1064ms의 단일 발생은 APM 메트릭의 최고치(783ms)보다 36% 높으며, S3 서비스 측 일시적 지연으로 인한 outlier로 판단된다.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | S3 HEAD 요청의 네트워크 지연으로 인한 latency spike | APM 메트릭에서 평균 420ms, 최고 783ms 관측. octree.rb:9에서 매 요청마다 S3 HEAD 호출 확인. 캐싱 없음. |
— | Confirmed |
| H2 | DB 쿼리 지연 (storage_option 조회) | storagable.rb:87에서 Rails.cache.fetch 사용 (1주 TTL) |
캐시 적중 시 DB 접근 없음. 캐시 만료 시에도 단순 조회로 수십ms 이하. S3 HEAD가 전체 시간의 대부분 차지. | Rejected |
| H3 | 대용량 octree 파일로 인한 S3 처리 지연 | — | S3 HEAD 요청은 파일 크기와 무관하게 메타데이터만 확인. 객체 크기는 HEAD latency에 영향 없음. | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
- 필요 없음: 단일 발생(1건)이며 기능적 오류 없이 200 OK 반환. 1064ms는 UX에 영향이 있을 수 있으나 critical은 아님.
단기 개선 (1주 이내)#
app/models/concerns/octree.rb:8-10:octree_uploaded?결과를 짧은 TTL(30-60초)로 인메모리 또는 Rails 캐시에 캐싱하는 방안 검토. 업로드 확인은 파일이 한번 존재하면 이후 항상 존재하므로, positive result는 영구 캐싱 가능.- S3 client에 타임아웃 설정 추가 검토 (
Aws::S3::Client초기화 시:http_open_timeout,:http_read_timeout옵션).
장기 개선: S3 Event Notification 전환#
S3 업로드 완료를 S3 Event Notification → SQS로 비동기 감지하는 방식으로 전환하면, 클라이언트의 polling 방식 HEAD 요청을 제거할 수 있다. compass-service에서 동일 패턴(aws_s3_bucket_notification → SQS → Lambda)을 이미 운영 중이므로 참조 가능.
변경 범위 분석#
영향받는 레포:
cupix-infrastructure(Terraform — S3/SQS 리소스)tesla(cupixworks-api — Rails 코드)- 클라이언트 (optional — polling 제거 시)
Infrastructure 변경 (cupix-infrastructure):
| 파일 | 변경 내용 |
|---|---|
cupix-service/sqs/main.tf |
octree upload event용 SQS queue + DLQ 추가 |
cupix-service/s3/base-region/main.tf |
aws_s3_bucket_notification 리소스 추가 (hosting bucket → SQS, prefix filter: */octree/) |
cupix-service/sqs/ (new) |
SQS queue policy (S3 → SQS SendMessage 허용) |
| IAM | API 서비스에 sqs:ReceiveMessage, sqs:DeleteMessage 권한 추가 |
현재 cupix-infrastructure/cupix-service/s3/base-region/main.tf에는 event notification 설정이 전혀 없으며, hosting bucket은 14개 리전에 걸쳐 생성됨. 각 리전별 hosting bucket에 notification을 추가해야 한다.
참고 구현 — compass-service (cupixworks/applications/compass-service/src/lambda-function/main.tf:261-270):
resource "aws_s3_bucket_notification" "pano_vectorize_event" {
bucket = aws_s3_bucket.analysis_model_bucket.id
queue {
queue_arn = aws_sqs_queue.pano_vectorize_queue.arn
events = ["s3:ObjectCreated:*"]
filter_prefix = "analyze_pano/"
filter_suffix = ".json"
}
}
API (tesla) 코드 변경:
| 파일 | 변경 내용 |
|---|---|
app/models/concerns/octree.rb |
check_octree_uploading 메서드를 DB 상태 확인 방식으로 변경 (S3 HEAD 제거) |
app/workers/ (new) |
SQS consumer worker 추가 — S3 event에서 object key 파싱 → Pointcloud 식별 → uploaded_octree_state 호출 |
app/models/concerns/aws_adapter/sqs.rb |
기존 SQS adapter 활용 가능 (이미 Aws::SQS::Client 래퍼 존재) |
config/routes.rb |
check_octree_uploading 엔드포인트 유지 (backward compatibility) — DB 상태만 조회하도록 변경 |
app/controllers/concerns/octree_controller.rb |
변경 없음 (repository 계층에서 처리) |
app/repositories/concerns/octree_repository.rb |
check_octree_uploading에서 S3 HEAD 대신 DB octree_state 확인으로 변경 |
SQS Worker 처리 흐름:
- S3 ObjectCreated event → SQS queue 수신
- Worker가 S3 event의
s3.object.key에서 pointcloud ID 추출 (octree_object_key패턴 역파싱) - 해당 Pointcloud의
octree_state를:uploaded로 전환 - 메시지 삭제
핵심 복잡도:
octree_object_key는 SHA1 hex prefix를 포함하므로 (octree_hex=Digest::SHA1.hexdigest(...)[:16]), S3 event의 key에서 pointcloud ID를 역추적하려면 DB lookup 또는 별도 매핑 테이블이 필요- 14개 리전 hosting bucket 각각에 notification 설정 필요
- 기존 클라이언트의 polling API와의 병행 운영 기간 필요
예상 작업량: Medium (2-3 sprint)
- Terraform 변경: 리전별 bucket notification + SQS queue (1 sprint)
- API worker 구현 + key 역파싱 로직: (1 sprint)
- 테스트 + 클라이언트 마이그레이션: (1 sprint)
Monitoring#
- APM p95/p99 duration 모니터 설정:
avg:trace.rack.request.duration{service:cupixworks-api,resource_name:api::v1::pointcloudscontroller_check_octree_uploading} > 1.0
- S3 HEAD 요청 실패율 모니터링 (현재는 에러 없이 지연만 발생)
Risk Assessment#
- Risk level: low
- 예상 복잡도: 단기(캐싱) trivial / 장기(S3 event notification) medium
- 단일 발생이며 기능적 장애 없음. S3 네트워크 지연에 의한 일시적 latency spike로, 구조적 결함보다는 인프라 특성에 가까움. 캐싱 도입으로 재발 빈도를 줄일 수 있으나 즉시 대응 필요성은 낮음.
- S3 event notification 전환은 14개 리전 버킷 × infra/API 양측 변경이 필요하여 2-3 sprint 규모이나, compass-service 선례가 있어 패턴은 검증됨.
Revision History#
Revision 1#
Feedback: S3 event notification 방식으로 변경하려면 얼마나 변경이 필요한지 확인해
판정:
| 피드백 항목 | 판정 | 근거 |
|---|---|---|
| S3 event notification 전환 범위 조사 | 수용 | cupix-infrastructure/cupix-service/s3/base-region/main.tf에 event notification 설정 부재 확인. tesla/app/models/concerns/octree.rb:8-9에서 S3 HEAD 직접 호출 확인. cupixworks/applications/compass-service/src/lambda-function/main.tf:261-270에서 동일 패턴의 참조 구현 확인. tesla/app/models/concerns/aws_adapter/sqs.rb에서 기존 SQS adapter 존재 확인. 14개 리전 hosting bucket(cupix-infrastructure/cupix-service/s3/outputs.tf:2-19) 각각에 notification 추가 필요. |
변경 사항:
- Fix Recommendation의 "장기 개선" 섹션을 구체적인 변경 범위 분석으로 확장 (영향 레포, 파일별 변경 내용, 예상 작업량)
- Risk Assessment에 장기 복잡도 반영
추가 조사 내용:
cupix-infrastructure/cupix-service/s3/base-region/main.tf— hosting bucket 정의 확인, event notification 미설정 확인cupixworks/applications/compass-service/src/lambda-function/main.tf— S3 → SQS → Lambda 참조 패턴 확인tesla/app/models/concerns/octree.rb—octree_object_key생성 로직 확인 (SHA1 prefix로 역파싱 복잡도 파악)tesla/app/models/concerns/aws_adapter/sqs.rb— 기존 SQS client adapter 존재 확인tesla/app/models/concerns/statable/pointcloud.rb:193-211— octree state machine 확인cupix-infrastructure/cupix-service/s3/outputs.tf— 14개 리전 hosting bucket 목록 확인