Api::V1::BimsController#check_grid_system_uploading (avg 16875ms, max 16875ms)
RCA: Api::V1::BimsController#check_grid_system_uploading (avg 16875ms, max 16875ms)
Overview#
What Happened#
2026-06-26 20:27:38 KST, cupixworks-api의 Api::V1::BimsController#check_grid_system_uploading 엔드포인트가 단일 요청에서 16,875ms 가 소요되어 latency 클러스터로 감지되었다. 요청 자체는 HTTP 200으로 정상 응답했고, 동일 시간대에 error/warn 로그는 없었다. APM 트레이스 한 건만 잡힌 산발성 slow request이다.
Quick Facts#
| Field | Value |
|---|---|
| resource_name | Api::V1::BimsController#check_grid_system_uploading |
| cluster_type | latency |
| avg_duration_ms | 16875 |
| max_duration_ms | 16875 |
| sample_trace_id | 1842124262015981138 |
| env | production, region us-west-2, tenant cupix |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| cupixworks-api / BIM upload | 1 | 사용자 1명이 BIM grid system 업로드 확인 요청에서 ~17초 대기 후 정상 응답 수신. 데이터 손상 없음. |
Timeline#
- 2026-06-26 20:27:38 KST — 사용자가
PUT /api/v1/bims/20358/check_grid_system_uploading호출 (Datadog APM 트레이스1842124262015981138, duration 16875ms). - 2026-06-26 20:27:55 KST — 동일 요청이 HTTP 200으로 응답 완료 (Datadog access log 기록 시각).
- 2026-06-26 20:22:25 KST 부터 — 같은 시간대에
svc:cupixworks-api::unknownscope의 incident2026-06-26-svc-cupixworks-api--unknown-2가 open 상태 (다른 클러스터9d0d9f6e-14e7-4a64-b9c1-e8a7f73c7b44와 묶임).
Error Log#
{
"resource_name": "Api::V1::BimsController#check_grid_system_uploading",
"service": "cupixworks-api",
"occurrences": 1,
"avg_ms": 16875,
"max_ms": 16875,
"sample_trace_id": "1842124262015981138"
}
Impact#
- Service:
cupixworks-api - 발생 횟수: 1
- 최초 발생: 2026-06-26 20:27:38 KST
- 최근 발생: 2026-06-26 20:27:38 KST
Root Cause Summary#
check_grid_system_uploading 엔드포인트는 @model.grid_system_uploaded? 를 통해 S3 객체 존재 여부를 Aws::S3::Object#exists? (S3 HEAD object 호출) 로 확인한다. 이 동기 HTTP 호출이 응답 시간 전체를 좌우하며, 해당 요청에서 S3 측 지연 또는 네트워크 슬로우(약 16~17초)가 발생하면서 요청 전체가 지연되었다. 코드에는 timeout, retry 정책, async 처리가 없어 외부 의존성 latency 가 응답에 그대로 전파되는 구조이다. 클러스터는 단일 발생 (occurrence_count: 1) 이므로 만성적인 성능 결함이 아니라 S3 측 transient slowness 가 직접 원인일 가능성이 높다. 다만 동일한 시간대 svc:cupixworks-api::unknown incident 가 열려 있어 광역 API degradation 가능성도 함께 검토해야 한다.
Technical Analysis#
Code Path#
- Entry point:
app/controllers/concerns/grid_system_controller.rb:4— controller action - Repository layer:
app/repositories/concerns/grid_system_repository.rb:4— state check + S3 verification 호출 - S3 lookup:
app/models/concerns/grid_system.rb:45-52—grid_system_uploaded?→grid_system_object.exists? - S3 object factory:
app/services/cupix/storage_service.rb:29-36—Aws::S3::Object.new생성 - Failure point:
app/models/concerns/grid_system.rb:28—grid_system_object.exists?(S3 HEAD 호출, 블로킹)
def check_grid_system_uploading
repository_instance.check_grid_system_uploading
render_api Renderable.new({
contents: @model
})
end
def check_grid_system_uploading
case @model.grid_system_state_name
when :uploading
raise Cupix::Errors::Resource.new(code: 'RESC10000', reason: 'grid_system does not uploaded') unless @model.check_grid_system_uploading
else
raise Cupix::Errors::InvalidState.new(code: 'STAT10000', reason: "Invalid state: #{@model.grid_system_state}")
end
@model
end
def grid_system_uploaded?
grid_system_object.exists?
end
def grid_system_object
Cupix::StorageService.object(
storage_option: storage_option,
bucket_name: storage_option.s3_hosting_bucket_name,
key: self.grid_system_object_key
)
end
# ...
def check_grid_system_uploading
if grid_system_uploaded?
uploaded_grid_system_state
true
else
false
end
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
Expected vs Actual: 정상 동작에서는 Aws::S3::Object#exists? (S3 HEAD object) 가 수십~수백 ms 내에 응답하여 컨트롤러 전체가 1초 미만에 완료된다. 실제로는 단일 요청에서 약 16.8초가 소요되었는데, 다른 동시 호출들은 동일 윈도우 내에서 정상 응답(상태 200, 로그 타임스탬프 간격 정상)을 보여 코드 자체의 회귀가 아니라 그 한 요청에서만 S3 호출 (또는 그 직전의 DB lookup set_bim) 이 길게 잠겼음을 시사한다. Aws::S3::Client 의 기본 timeout/retry 가 활성화된 상태에서 transient slowness 가 retry 누적으로 증폭되었을 가능성이 가장 자연스러운 시나리오이다.
Log Evidence#
Datadog 쿼리 (cluster 파일의 ## Datadog 섹션 그대로):
service:cupixworks-api resource_name:"Api::V1::BimsController#check_grid_system_uploading" env:production @duration:>500ms
해당 요청의 access log (KST 변환):
2026-06-26 20:27:55 KST info [200] PUT /api/v1/bims/20358/check_grid_system_uploading (Api::V1::BimsController#check_grid_system_uploading)
검색 쿼리:
service:cupixworks-api "/api/v1/bims/20358/check_grid_system_uploading"
2026-06-26T11:20:00Z ~ 2026-06-26T11:35:00Z → 1 hit
동시간대 동일 컨트롤러 호출들은 모두 정상 응답 시각을 가짐 (대표 샘플):
2026-06-26 20:22:37 KST [200] PUT /api/v1/bims/20363/check_grid_system_uploading
2026-06-26 20:22:53 KST [200] PUT /api/v1/bims/20368/check_grid_system_uploading
2026-06-26 20:25:10 KST [200] PUT /api/v1/bims/20362/check_grid_system_uploading
2026-06-26 20:25:23 KST [200] PUT /api/v1/bims/20361/check_grid_system_uploading
2026-06-26 20:25:35 KST [200] PUT /api/v1/bims/20367/check_grid_system_uploading
2026-06-26 20:25:45 KST [200] PUT /api/v1/bims/20360/check_grid_system_uploading
2026-06-26 20:26:21 KST [200] PUT /api/v1/bims/20369/check_grid_system_uploading
2026-06-26 20:26:31 KST [200] PUT /api/v1/bims/20364/check_grid_system_uploading
2026-06-26 20:27:55 KST [200] PUT /api/v1/bims/20358/check_grid_system_uploading ← slow
동일 시간 윈도우(2026-06-26T11:20:00Z ~ 11:35:00Z) 에서 service:cupixworks-api status:error 검색 결과 0건, 같은 윈도우의 status:warn 은 모두 20:34 이후의 _update_document "NotFound - attributes_in_database" 로 본 트레이스와 무관 (Elasticsearch indexer 쪽). S3 timeout/error 로그도 없음 — 즉, 호출은 결국 성공했고 단지 느렸다.
Status board scope svc:cupixworks-api::unknown 의 active incident (uncertain — 자동 클러스터링 결과):
id: 2026-06-26-svc-cupixworks-api--unknown-2
started_at: 2026-06-26T11:22:25.574Z (KST 2026-06-26 20:22:25)
cluster_ids: [9d0d9f6e-14e7-4a64-b9c1-e8a7f73c7b44, 66b12e69-...]
같은 날 01:25 KST 부터 비슷한 svc:cupixworks-api::unknown incident가 4건 발생/해소되었음 — 광역 latency 패턴이 반복되고 있음을 시사하나, 본 클러스터 한 건만으로 광역 원인을 단정하기에는 evidence 부족 (uncertain -- needs verification, 트레이스 단위 span breakdown 으로 DB vs S3 시간 분리 필요).
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | Aws::S3::Object#exists? (S3 HEAD) 호출 자체에서 transient slowness 발생 |
grid_system_uploaded? 가 컨트롤러 path 의 유일한 외부 I/O 호출이며 별도 timeout 없음 (app/models/concerns/grid_system.rb:27-29). 같은 시각 다른 호출은 정상 → 코드 회귀가 아닌 외부 의존성 transient. |
직접 S3 latency 메트릭/에러 로그를 확인하지 못함. APM span 단위 breakdown 으로 검증 필요. | Confirmed (most likely) |
| H2 | set_bim 또는 repository_instance.show(params[:id]) 의 ActiveRecord lookup (PostgreSQL) 지연 |
before_action :set_bim 이 모든 요청에 적용 (app/controllers/api/v1/bims_controller.rb:9). DB slow query 가 S3 호출 전 동일 지연 유발 가능. |
DB slow query 로그 또는 PG warnings 가 동일 윈도우에 없음 (status:warn/status:error 0건 BIM 관련). 단정할 직접 증거 부족. |
Inconclusive |
| H3 | 코드 회귀로 인한 만성 latency | — | 같은 시간대 다른 9건의 check_grid_system_uploading 호출이 모두 정상 응답 (access log). 클러스터 occurrence_count=1 (단발). |
Rejected |
| H4 | 광역 cupixworks-api degradation 의 영향 (status board svc:*::unknown incident) |
같은 시각 또 다른 cluster 9d0d9f6e-14e7-4a64-b9c1-e8a7f73c7b44 와 함께 incident open. 같은 날 4건의 유사 incident 반복. |
본 클러스터는 단일 trace 1건 (1 occurrence). 다른 cluster 가 동일 root cause 인지는 미확인 (uncertain). | Inconclusive |
Fix Recommendation#
즉시 조치 (Critical)#
- 사용자 영향이 단발성(1건, HTTP 200 정상 응답) 이므로 긴급 코드 변경은 불필요. 동일 패턴 재발 여부를 모니터링한다.
- APM trace
1842124262015981138의 span breakdown 을 Datadog 에서 확인하여 16.8초 중 PostgreSQLBim.find와Aws::S3::Object#exists?가 차지한 시간 비율을 분리 (flame graph→ trace 상세). 이 confirm 없이 H1 vs H2 판정을 굳히지 말 것.
단기 개선 (1주 이내)#
app/services/cupix/storage_service.rb:29-36의Aws::S3::Object생성 경로에 명시적http_read_timeout,http_open_timeout,retry_limit을 설정하는 방향 검토. 현재는 SDK 기본값에 의존 — 기본 retry(=3) × 기본 timeout 조합으로 best-case 응답을 두 자릿수 초 단위로 늘릴 수 있다.app/controllers/concerns/grid_system_controller.rb:4의check_grid_system_uploading는 사용자 polling 용 short-lived 엔드포인트이므로, S3 HEAD 호출에 짧은 timeout (예: 2~3초) 을 적용하고 timeout 시에는 "아직 업로드 안 됨" 상태로 응답하는 방향이 사용자 경험상 더 적절. 구체 timeout 값은 운영 합의 후 결정.- 동일 endpoint 의 latency 분포를 Datadog dashboard 에 추가 (아래 Monitoring 섹션 참조).
장기 개선 (재발 방지)#
- BIM grid system 업로드 상태는 S3 HEAD 폴링이 아니라 S3 event notification (또는 presigned PUT 응답 후 클라이언트 ACK) 으로 전환하면 S3 의존 latency 자체를 제거할 수 있다. 이 변경은
grid_system_statestate machine (app/models/concerns/grid_system.rb:7-25) 의 transition trigger 를 server-driven 으로 옮기는 작업을 포함한다. svc:cupixworks-api::unknown의 반복적 incident 패턴 (06-24 ~ 06-26 사이 5건 이상) 에 대해 별도의 광역 RCA 가 필요. 본 cluster 의 fix 와 분리해 추적.
Monitoring#
writing-datadog-monitoring-queries 룰에 따라 timeseries widget 에 그대로 들어갈 수 있는 형태의 쿼리를 사용한다.
엔드포인트 p95 latency 추이:
p95:trace.rack.request{service:cupixworks-api,resource_name:api::v1::bimscontroller#check_grid_system_uploading}
같은 컨트롤러의 호출 처리량:
sum:trace.rack.request.hits{service:cupixworks-api,resource_name:api::v1::bimscontroller#check_grid_system_uploading}.as_rate()
API 전반의 p95 latency (광역 degradation 추적):
p95:trace.rack.request{service:cupixworks-api,env:production}
S3 HEAD 호출 latency (광역, Aws::S3 span):
p95:trace.aws.command{service:cupixworks-api,aws_service:s3,aws_operation:head_object}
위 쿼리는 Datadog APM 에서 자동 수집되는 metric 가용성에 따라 다를 수 있다 — 현재 환경에서
trace.rack.request{resource_name:...}시리즈가 비어 있는 것이 확인되어 (metric query empty) widget 추가 시 actual metric 이름을 한 번 더 검증할 것 (uncertain -- needs verification).
알람 후보 (참고용, monitor 문법으로 별도 작성):
Api::V1::BimsController#check_grid_system_uploadingp95 > 5s, 10분 윈도우cupixworks-api전체 error rate > 1%, 5분 윈도우
Risk Assessment#
- Risk level: low (단일 사용자, 단발 발생, HTTP 200 정상 응답, 데이터 손상/유실 없음)
- 예상 복잡도: trivial (즉시 조치는 모니터링만), standard (timeout 도입 시), critical (S3 event notification 으로 폴링 제거하는 장기 개선 시)