ES /docs

Api::V1::SitetracksController#check_uploading (avg 77774ms, max 77774ms)

RCA: Api::V1::SitetracksController#check_uploading latency (77774ms)

Overview#

What Happened#

2026-07-30 20:34 KST 경 Api::V1::SitetracksController#check_uploading 리소스에서 77.7초에 달하는 단일 latency trace 가 발생했다. 응답 자체는 오류가 아닌 latency 클러스터이며, 같은 시각 cupixworks-api 서비스 전반의 요청 지연이 baseline 대비 3~5배 상승한 자동 감지 인시던트(2026-07-30-svc-cupixworks-api--unknown-1, 21:23 KST 자동 해소)의 첫 클러스터다. 같은 인시던트에 4개의 다른 latency 클러스터(PointcloudsController#cpc_mesh_upload_url, BadgesController#index, FieldsController#index 등)가 함께 묶여 있다.

Quick Facts#

Field Value
resource_name Api::V1::SitetracksController#check_uploading
service cupixworks-api
cluster_type latency
avg_duration_ms 77774
max_duration_ms 77774
entry point app/controllers/api/v1/sitetracks_controller.rb:36-41
region us-west-2
tenant cupix
sample_trace_id 7390544816261687305
env production

Affected Teams#

Team / Domain Error Count Impact
cupixworks-api (Sitetrack upload flow) 1 slow trace 사이트트랙 업로드 완료 확인(check_uploading) 요청이 77초 대기 — 사용자 관점에서 업로드 성공 감지가 지연되거나 클라이언트 timeout 로 실패 처리될 수 있음. 동일 인시던트에서 5개의 latency 클러스터가 묶여 있음.

Timeline#

  1. 2026-07-30 20:34:05 KST — 본 클러스터에 해당하는 SitetracksController#check_uploading 77.7s trace 발생 (first_seen). 자동 인시던트 감지 시작 (svc:cupixworks-api::unknown, 첫 클러스터).
  2. 2026-07-30 20:35:27 KST — 두 번째 latency 클러스터 e758e925 발생.
  3. 2026-07-30 21:05~21:23 KSTcupixworks-api 전반 avg request duration 이 baseline (0.30.9s) 에서 2.02.6s 로 상승, 요청 rate 2560 → 80100 req/s.
  4. 2026-07-30 21:05:28 KSTPointcloudsController#cpc_mesh_upload_url 19s trace (dfa0ed54).
  5. 2026-07-30 21:06:40 KSTBadgesController#index 12.4s trace (1feaf5c5).
  6. 2026-07-30 21:23:30 KSTFieldsController#index 36.7s trace (da6d4c75), 인시던트 자동 해소.

Error Log#

Datadog Logs

text
{
  "resource_name": "Api::V1::SitetracksController#check_uploading",
  "service": "cupixworks-api",
  "occurrences": 1,
  "avg_ms": 77774,
  "max_ms": 77774,
  "sample_trace_id": "7390544816261687305"
}

Impact#

  • Service: cupixworks-api
  • 발생 횟수: 1
  • 최초 발생: 2026-07-30 20:34 KST
  • 최근 발생: 2026-07-30 20:34 KST

Root Cause Summary#

이 클러스터는 개별 코드 결함이 아니라, 해소된 서비스 전반 성능 저하 인시던트(2026-07-30-svc-cupixworks-api--unknown-1) 의 시작점으로 발생한 단발성 slow trace 다. check_uploading 경로는 SitetrackResult::S3#check_uploading 에서 S3 list_objects_v2 를 호출하고 상태 전이(uploaded_sitetrack_state) 를 수행하는 I/O 바운드 작업이며, 정상 baseline 은 수백 ms수 초 수준이다. 인시던트 창구(20:3421:23 KST) 동안 서비스 전반 avg request duration 이 35배 (약 0.30.9s → 22.6s) 상승했고 요청 rate 도 23배로 뛰어 컨테이너 request-handling 용량이 포화된 상태에서, 이 단일 요청이 (a) Rack request queue / 스레드 대기, (b) 하위 S3 API 응답 지연/재시도, (c) 상태 전이 시 DB lock 대기 중 하나 또는 조합으로 77s 까지 늘어난 것으로 판단된다. 다만 이 클러스터의 개별 trace flame graph 로 어느 span 이 시간을 소비했는지 직접 확인하지는 못했으므로 개별 요인 비중은 uncertain — needs verification. 근본 원인은 sitetracks 코드 자체가 아니며, 상위 인시던트의 원인(현재 root_cause_types: [unknown] 으로 미분류) 이 규명되어야 이 클러스터도 재발 방지된다.

Technical Analysis#

Code Path#

  • Entry point: app/controllers/api/v1/sitetracks_controller.rb:36-41SitetracksController#check_uploading
  • Repository: app/repositories/sitetrack_repository.rb:229-232SitetrackRepository#check_uploading
  • Model concern (실질 작업): app/models/concerns/sitetrack_result/s3.rb:41-44SitetrackResult::S3#check_uploading
  • S3 listing (I/O 병목 후보): app/services/cupix/storage_service.rb:64-79Cupix::StorageService.object_list → AWS list_objects_v2
app/controllers/api/v1/sitetracks_controller.rb:36-41ruby
def check_uploading
  @model = repository_instance.check_uploading
  render_api Renderable.new({
    contents: @model
  })
end

SitetrackRepository#check_uploading 은 로드된 @model 로 위임한다.

app/repositories/sitetrack_repository.rb:229-232ruby
def check_uploading
  @model.check_uploading
  @model
end

실제 작업은 SitetrackResult::S3#check_uploading 에서 (1) S3 오브젝트 키 목록 조회 → (2) 상태 전이(uploaded_sitetrack_state) 두 단계로 이루어진다.

app/models/concerns/sitetrack_result/s3.rb:41-44ruby
def check_uploading
  self.sitetrack_objects = sitetrack_object_key_list
  self.uploaded_sitetrack_state
end

sitetrack_object_key_listCupix::StorageService.object_key_list 를 호출하고, 그 내부에서 object_list → AWS SDK list_objects_v2 를 실행한다.

app/services/cupix/storage_service.rb:64-89ruby
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

def object_key_list(storage_option: nil, **kwargs)
  opts = parse_storage_option(storage_option).merge(kwargs)

  check_required_params(opts, %i[region bucket_name prefix])

  object_list(storage_option: storage_option, **kwargs).map do |object|
    object.key.split(opts[:prefix])[1]
  end
end

기대 동작: check_uploading 은 baseline 수백 ms~수 초 이내에 응답한다. 실제 동작: 인시던트 창구 시작 시점에 단일 요청이 77.7s 걸림. 같은 창구에 다른 4개 latency 클러스터가 함께 트리거되어 sitetracks 만의 문제가 아니라 서비스 전반 부하 패턴임을 시사.

Log Evidence#

같은 시각 SitetracksController#check_uploading 요청 상태 (모두 200):

Datadog query:

text
service:cupixworks-api "SitetracksController#check_uploading"

인시던트 창구(20:34~21:08 KST) 안의 check_uploading 호출 예시 (모두 성공):

text
2026-07-30 20:35:07  [200] PUT /api/v1/sitetracks/22579/check_uploading
2026-07-30 20:35:23  [200] PUT /api/v1/sitetracks/22579/check_uploading
2026-07-30 20:36:17  [200] PUT /api/v1/sitetracks/22587/check_uploading
2026-07-30 20:36:47  [200] PUT /api/v1/sitetracks/3167/check_uploading
2026-07-30 20:37:11  [200] PUT /api/v1/sitetracks/22547/check_uploading
2026-07-30 20:42:38  [200] PUT /api/v1/sitetracks/3166/check_uploading
2026-07-30 20:53:48  [200] PUT /api/v1/sitetracks/3151/check_uploading
2026-07-30 20:54:39  [200] PUT /api/v1/sitetracks/3160/check_uploading
2026-07-30 20:59:46  [200] PUT /api/v1/sitetracks/22575/check_uploading
2026-07-30 21:05:12  [200] PUT /api/v1/sitetracks/1189/check_uploading
2026-07-30 21:07:53  [200] PUT /api/v1/sitetracks/22598/check_uploading
2026-07-30 21:08:17  [200] PUT /api/v1/sitetracks/1190/check_uploading

응답 코드는 모두 200 — 오류 없이 latency 만 튐. cluster_type=latency 와 일치. first_seen 시각(11:34:05Z = 20:34:05 KST) 직후 20:35:07 KST 에 첫 로그가 확인됨.

서비스 전반 avg request duration (3h 기준 timeseries):

Datadog query:

text
avg:trace.rack.request.duration{service:cupixworks-api}

Baseline (19:0020:30 KST) 은 대부분 0.30.9s 수준이나, 인시던트 창구(20:3421:23 KST) 에서 2.02.6s 로 상승:

text
... 0.428, 0.710, 0.901, 0.817, 0.760, 0.724, 0.702, 0.727, 0.575,
    0.417, 0.434, 0.425, 0.430, 0.477, 0.385, 0.316, 0.559,
    2.033, 2.317, 1.771, 1.162, 1.168, 1.064, 0.912, 0.825, 1.247,
    1.725, 1.935, 1.771, 2.208, 2.284, 2.157, 2.369, 2.576, ...

요청 rate 상승 (동일 창구):

Datadog query:

text
sum:trace.rack.request.hits{service:cupixworks-api}.as_rate()
text
... 29.45, 30.82, 33.45, 37.52, 39.43, 42.4, 44.67, 44.92, 50.73, 57.1, 56.75, 58.8, 56.67,
    42.82, 72, 61.6, 61.77, 101.15, 75.52, 66.65, 51.28, 53.7, 68.7, 55.05, 56.08, 74.93,
    68, 40.63, 45.4, 61.53, 63.33, 48.13, 69.33, ...

Baseline 2560 req/s → 인시던트 창구 60100 req/s (peak 101).

AWS S3 command latency 는 baseline 수준:

Datadog query:

text
avg:trace.aws.command.duration{service:cupixworks-api}

인시던트 창구 값이 대부분 0.3~0.8s 로 baseline 대비 크게 벗어나지 않음:

text
... 0.485, 0.394, 0.455, 0.523, 0.548, 0.655, 0.579, 0.607, 0.553, 0.573, 0.637, 0.847,
    0.807, 0.506, 0.485, 0.465, 0.440, 0.445, 0.657, 0.374, 0.330, 0.316, 0.338, 0.366, 0.486, ...

즉 서비스 전체 AWS API 호출 평균은 크게 상승하지 않음. 다만 이 metric 은 aggregate 이므로 개별 outlier(단일 77s trace 안의 특정 S3 호출) 를 배제하지는 못한다 — uncertain — needs verification (개별 trace flame graph 확인 필요).

Status board 컨텍스트:

text
$ bun run cli/incident-board.ts for-cluster 9855766b-3975-47ac-9d01-4984a543fba9
json
{
  "scope": "svc:cupixworks-api::unknown",
  "active": null,
  "recent": [{
    "id": "2026-07-30-svc-cupixworks-api--unknown-1",
    "title": "cupixworks-api service degraded",
    "status": "resolved",
    "started_at": "2026-07-30T11:34:05.124Z",
    "resolved_at": "2026-07-30T12:23:30.350Z",
    "cluster_ids": [
      "9855766b-3975-47ac-9d01-4984a543fba9",
      "e758e925-3b09-4acf-bb97-4468f619239e",
      "dfa0ed54-7545-4c81-8023-e7def3db3669",
      "1feaf5c5-af3f-4902-96a8-537a72bd4d9e",
      "da6d4c75-28f5-4ac7-a8a1-721df2ead8c3"
    ]
  }]
}

본 클러스터가 인시던트의 첫 이벤트(started_atfirst_seen 동일)이며, 총 5개 latency 클러스터가 ~50분 창구에 몰려 발생 후 자동 해소됨.

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 서비스 전반 부하 상승으로 인한 request handling 경합 (sitetracks 코드 자체는 무결) (a) 동일 창구에 4개 다른 resource 의 latency 클러스터가 같은 svc 스코프로 자동 그룹화됨. (b) 서비스 avg request duration 35x 상승. (c) 요청 rate 23x 상승 (peak 101 req/s). (d) SitetracksController#check_uploading 응답 로그는 모두 200. (e) 인시던트 자동 해소 후 baseline 회복. Confirmed (proximate)
H2 SitetrackResult::S3#check_uploading 의 S3 list_objects_v2 호출이 개별 지연 (예: 특정 prefix 에 대량 오브젝트, S3 스로틀, TCP 리트라이) 코드상 object_list 는 pagination 없이 list_objects_v2 단일 호출 후 .contents 필터링만 수행. 대량 오브젝트/스로틀 시 latency 는 실제로 늘 수 있음. avg:trace.aws.command.duration 은 aggregate 라 outlier 감춰질 수 있음. 인시던트 창구의 avg:trace.aws.command.duration{service:cupixworks-api} 이 대부분 0.3~0.8s 로 baseline 유지 (77s 를 aggregate 로 밀 만한 폭 없음). 다른 4개 클러스터는 S3 를 사용하지 않는 resource (BadgesController#index, FieldsController#index) 도 포함. Rejected as primary — S3 는 부차적 병목이나 근본 원인 아님
H3 상태 전이(uploaded_sitetrack_state) 에서 DB lock 대기 / row lock 경합 check_uploading 이 상태 전이를 포함하므로 DB write 발생. 인시던트 창구에서 write 경합 가능성 존재. 같은 창구에 BadgesController#index, FieldsController#index 같은 read-only 요청도 함께 지연 → sitetracks write 경합만으로는 설명 불가. Rejected as primary — 필요 시 개별 trace 로 확인
H4 Elasticsearch backend 자체 지연 ES 는 latency-민감 데이터 저장소. check_uploading 은 ES 를 사용하지 않는 코드 경로 (Cupix::StorageService + AR 상태 전이). 같은 인시던트의 BadgesControllerget_badges/_search avg duration 이 5~30ms baseline 유지 (BadgesController RCA 참조). Rejected
H5 특정 배포로 인한 회귀 인시던트가 좁은 시간 창구에서 발생 후 자동 해소. 배포 SHA/이벤트를 확인하지 못함 (uncertain — needs verification). 자동 해소된 점은 부하 완화로도 설명 가능. Inconclusive — needs verification
H6 클라이언트 재시도 폭주 (같은 sitetrack 22579 를 20:35:07 및 20:35:23 KST 두 번 호출) Datadog 로그에 동일 sitetrack id 에 대한 check_uploading 반복 호출 관찰. 폴링/재시도 로직이 slow response 를 트리거하는 클라이언트 쪽 원인일 가능성. 반복이 16초 간격 (짧지 않음). 폭주라 부르기는 어려움. Inconclusive — needs verification (client-side 로직 확인 필요)

Fix Recommendation#

즉시 조치 (Critical)#

  • 단일 이벤트이며 이미 해소된 상위 인시던트(2026-07-30-svc-cupixworks-api--unknown-1) 의 첫 클러스터이므로, 이 클러스터 단독으로 즉시 코드 수정은 불필요.
  • 재발 감지를 위해 status board 및 아래 Monitoring 섹션 쿼리로 관찰 계속.

단기 개선 (1주 이내)#

  • trace_id:7390544816261687305 의 APM flame graph 를 확인해 77.7s 가 어느 span (rack queue / aws.command.list_objects_v2 / mysql uploaded_sitetrack_state update / 기타) 에 분포되어 있는지 규명. Datadog APM trace 링크가 클러스터 상단 URL 에 그대로 존재.
  • 같은 창구에 묶인 다른 4개 latency 클러스터(e758e925, dfa0ed54, 1feaf5c5, da6d4c75) 의 span 분포와 교차 비교해 공통 병목(rack queue vs DB vs 외부 API) 을 특정. 4개 리소스가 서로 다른 backing store 를 쓰므로 공통 span 이 request queue/스레드 대기라면 인프라 튜닝 방향, 특정 리소스만 심하면 endpoint 최적화 방향.
  • Cupix::StorageService.object_listlist_objects_v2 결과를 pagination 없이 .contents 만 취급 (app/services/cupix/storage_service.rb:64-79). 특정 sitetrack prefix 에 오브젝트 수가 많거나 continuation token 이 필요한 경우 첫 페이지만 반환하는 잠재 정합성 문제가 있으니, 별도 이슈로 대량 prefix 케이스를 검증 (본 인시던트의 primary cause 는 아님, 참고).

장기 개선 (재발 방지)#

  • 서비스 전반의 부하 급증 시 자동 감지·알림을 강화. 현재 svc:*::unknown 스코프로만 자동 그룹핑되고 있어 root_cause 가 미분류 (root_cause_types: [unknown]). request rate + duration 상관 알림을 별도로 구성해 부하 급증 시나리오를 별도 스코프로 분리.
  • Puma / 컨테이너 동시성 metric (worker/thread busy, queued requests) 을 Datadog 로 노출해 다음 유사 인시던트에서 request queue 병목을 즉시 확인 가능하도록 계측.
  • check_uploading 같이 I/O 바운드 폴링 endpoint 는 서버 timeout (예: Puma worker-level or Rack middleware) 을 짧게 설정하고, 클라이언트가 재시도하도록 유도. 현재 77s 응답을 그대로 반환한 것은 서버 timeout 이 여유로움을 시사 (uncertain — Puma 설정 미확인).

Monitoring#

Datadog 쿼리 예시:

text
avg:trace.rack.request.duration{service:cupixworks-api}
text
sum:trace.rack.request.hits{service:cupixworks-api}.as_rate()
text
avg:trace.rack.request.duration{service:cupixworks-api,resource_name:api::v1::sitetrackscontroller#check_uploading}
text
avg:trace.aws.command.duration{service:cupixworks-api}

각 쿼리 모두 timeseries widget 에 그대로 삽입 가능. count by(...) / | stats 같은 monitor-only 문법은 사용하지 않음.

Risk Assessment#

  • Risk level: low — 단일 latency 이벤트, 이미 해소, 오류 아님 (200 응답).
  • 예상 복잡도: trivial (이 클러스터 단독 관점). 상위 인시던트 원인 규명은 별도로 추적 필요.