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#
- 2026-07-30 20:34:05 KST — 본 클러스터에 해당하는
SitetracksController#check_uploading77.7s trace 발생 (first_seen). 자동 인시던트 감지 시작 (svc:cupixworks-api::unknown, 첫 클러스터). - 2026-07-30 20:35:27 KST — 두 번째 latency 클러스터
e758e925발생. - 2026-07-30 21:05~21:23 KST —
cupixworks-api전반 avg request duration 이 baseline (0.30.9s) 에서 2.02.6s 로 상승, 요청 rate 2560 → 80100 req/s. - 2026-07-30 21:05:28 KST —
PointcloudsController#cpc_mesh_upload_url19s trace (dfa0ed54). - 2026-07-30 21:06:40 KST —
BadgesController#index12.4s trace (1feaf5c5). - 2026-07-30 21:23:30 KST —
FieldsController#index36.7s trace (da6d4c75), 인시던트 자동 해소.
Error Log#
{
"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-41—SitetracksController#check_uploading - Repository:
app/repositories/sitetrack_repository.rb:229-232—SitetrackRepository#check_uploading - Model concern (실질 작업):
app/models/concerns/sitetrack_result/s3.rb:41-44—SitetrackResult::S3#check_uploading - S3 listing (I/O 병목 후보):
app/services/cupix/storage_service.rb:64-79—Cupix::StorageService.object_list→ AWSlist_objects_v2
def check_uploading
@model = repository_instance.check_uploading
render_api Renderable.new({
contents: @model
})
end
SitetrackRepository#check_uploading 은 로드된 @model 로 위임한다.
def check_uploading
@model.check_uploading
@model
end
실제 작업은 SitetrackResult::S3#check_uploading 에서 (1) S3 오브젝트 키 목록 조회 → (2) 상태 전이(uploaded_sitetrack_state) 두 단계로 이루어진다.
def check_uploading
self.sitetrack_objects = sitetrack_object_key_list
self.uploaded_sitetrack_state
end
sitetrack_object_key_list 는 Cupix::StorageService.object_key_list 를 호출하고, 그 내부에서 object_list → AWS SDK list_objects_v2 를 실행한다.
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:
service:cupixworks-api "SitetracksController#check_uploading"
인시던트 창구(20:34~21:08 KST) 안의 check_uploading 호출 예시 (모두 성공):
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:
avg:trace.rack.request.duration{service:cupixworks-api}
Baseline (19:0020:30 KST) 은 대부분 0.30.9s 수준이나, 인시던트 창구(20:3421:23 KST) 에서 2.02.6s 로 상승:
... 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:
sum:trace.rack.request.hits{service:cupixworks-api}.as_rate()
... 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:
avg:trace.aws.command.duration{service:cupixworks-api}
인시던트 창구 값이 대부분 0.3~0.8s 로 baseline 대비 크게 벗어나지 않음:
... 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 컨텍스트:
$ bun run cli/incident-board.ts for-cluster 9855766b-3975-47ac-9d01-4984a543fba9
{
"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_at 과 first_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 3SitetracksController#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 상태 전이). 같은 인시던트의 BadgesController 는 get_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 / mysqluploaded_sitetrack_stateupdate / 기타) 에 분포되어 있는지 규명. 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_list는list_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 쿼리 예시:
avg:trace.rack.request.duration{service:cupixworks-api}
sum:trace.rack.request.hits{service:cupixworks-api}.as_rate()
avg:trace.rack.request.duration{service:cupixworks-api,resource_name:api::v1::sitetrackscontroller#check_uploading}
avg:trace.aws.command.duration{service:cupixworks-api}
각 쿼리 모두 timeseries widget 에 그대로 삽입 가능. count by(...) / | stats 같은 monitor-only 문법은 사용하지 않음.
Risk Assessment#
- Risk level: low — 단일 latency 이벤트, 이미 해소, 오류 아님 (200 응답).
- 예상 복잡도: trivial (이 클러스터 단독 관점). 상위 인시던트 원인 규명은 별도로 추적 필요.