ES /docs

Api::V1::BimsController#check_grid_system_uploading (avg 4316ms, max 4316ms)

RCA: BimsController#check_grid_system_uploading Latency (4316ms)

Overview#

What Happened#

2026-06-04 07:17 KST에 cupixworks-api의 Api::V1::BimsController#check_grid_system_uploading 엔드포인트가 4316ms로 응답하여 500ms 임계치를 초과했다. 요청 자체는 HTTP 200으로 성공했으나, 동일 호스트의 과도한 Pano 처리 부하와 S3 HEAD 요청 지연이 결합되어 비정상적 지연이 발생했다.

Quick Facts#

Field Value
resource_name Api::V1::BimsController#check_grid_system_uploading
duration 4292.55ms (DB: 253.68ms, View: 0.09ms)
top_frame app/models/concerns/grid_system.rb:28
env production, us-west-2
deploy production-us-west-2-20260602t0634z0
host ip-10-1-19-190.us-west-2.compute.internal

Affected Teams#

Team / Domain Error Count Impact
sellen (team ID 1170) 1 BIM 업로드 워크플로우에서 일시적 지연, 기능 실패 없음

Timeline#

  1. 2026-06-04 07:16 KST — 사용자(davidd@sellen.com)가 BIM 18669 업로드 워크플로우 시작 (show, update)
  2. 2026-06-04 07:17 KSTgrid_system_upload_url 요청 (581ms)
  3. 2026-06-04 07:17:55 KSTcheck_grid_system_uploading 요청 시작, 4292ms 소요
  4. 2026-06-04 07:18:01 KST — 요청 완료 (HTTP 200), 이벤트 발행 및 Facility 캐시 리셋

Error Log#

Datadog Logs

json
{
  "resource_name": "Api::V1::BimsController#check_grid_system_uploading",
  "service": "cupixworks-api",
  "occurrences": 1,
  "avg_ms": 4316,
  "max_ms": 4316,
  "sample_trace_id": "2458764040887365654"
}

Impact#

  • Service: cupixworks-api
  • 발생 횟수: 1
  • 최초 발생: 2026-06-04 07:17 KST
  • 최근 발생: 2026-06-04 07:17 KST

Root Cause Summary#

호스트 ip-10-1-19-190이 대량의 Pano 처리 요청(초당 50건 이상)으로 과부하 상태에서, check_grid_system_uploading 요청이 해당 호스트에 라우팅되었다. 이 액션은 S3 HEAD 요청(grid_system_object.exists?)을 수행하는데, 호스트의 리소스 경합으로 인해 Ruby 프로세스 큐잉 지연과 S3 응답 지연이 결합되어 총 4292ms가 소요되었다. DB 시간은 253ms에 불과하여, 약 4초의 미설명 시간은 프로세스 큐잉 대기 및 S3 네트워크 호출에서 발생한 것으로 확인된다.

Technical Analysis#

Code Path#

  • Entry point: app/controllers/concerns/grid_system_controller.rb:4
  • Permission join query (set_bim): app/repositories/bim_repository.rb:138-314
  • S3 existence check: app/models/concerns/grid_system.rb:28
  • State transition: app/models/concerns/grid_system.rb:46
  • Serialization (presigned URL): app/serializers/grid_system_attribute.rb:6-7

요청 흐름:

  1. before_action :set_bim — 복잡한 permission JOIN으로 BIM 레코드 로드
app/repositories/bim_repository.rb:138ruby
def self.permission_joins(user, team, ...)
  # 10+ LEFT JOINs for permission checking
end
  1. check_grid_system_uploading 액션 — S3 HEAD 요청으로 파일 존재 여부 확인
app/controllers/concerns/grid_system_controller.rb:4-9ruby
def check_grid_system_uploading
  repository_instance.check_grid_system_uploading
  render_api Renderable.new({
    contents: @model
  })
end
  1. Repository에서 state 확인 후 모델 메서드 호출
app/repositories/concerns/grid_system_repository.rb:4-13ruby
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
  1. Failure point — S3 HEAD 요청 (네트워크 I/O)
app/models/concerns/grid_system.rb:27-29ruby
def grid_system_uploaded?
  grid_system_object.exists?
end
app/models/concerns/grid_system.rb:31-36ruby
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

grid_system_object.exists?는 AWS S3에 HEAD 요청을 보내 객체 존재 여부를 확인한다. 정상 시 50-200ms이지만, 호스트 부하 상태에서는 수 초까지 지연될 수 있다.

  1. 성공 시 state machine 전환 및 저장
app/models/concerns/grid_system.rb:45-52ruby
def check_grid_system_uploading
  if grid_system_uploaded?
    uploaded_grid_system_state
    true
  else
    false
  end
end

Log Evidence#

사용한 Datadog 쿼리:

text
service:cupixworks-api resource_name:"Api::V1::BimsController#check_grid_system_uploading" @duration:>500ms
text
service:cupixworks-api @request_id:3600971c-a3d0-4084-9ec2-7a7e051bb430

핵심 로그 — 느린 요청:

json
{
  "timestamp": "2026-06-03T22:18:01.223Z",
  "resource_name": "Api::V1::BimsController#check_grid_system_uploading",
  "method": "PUT",
  "path": "/api/v1/bims/18669/check_grid_system_uploading",
  "status": 200,
  "duration": 4292.55,
  "db_runtime": 253.68,
  "view_runtime": 0.09,
  "host": "ip-10-1-19-190.us-west-2.compute.internal",
  "user": "davidd@sellen.com",
  "team_id": 1170
}

정상 비교 (동일 엔드포인트, 다른 호스트):

json
{
  "timestamp": "2026-06-03T22:16:23.092Z",
  "resource_name": "Api::V1::BimsController#check_grid_system_uploading",
  "bim_id": 18668,
  "duration": 286.55,
  "db_runtime": 20.17,
  "host": "ip-10-1-144-228"
}

호스트 부하 증거 — 동일 호스트에서 초당 50건 이상의 Pano 요청 처리 중:

text
service:cupixworks-api host:ip-10-1-19-190 @http.method:PUT

호스트에서 다수의 warn 로그 확인:

text
"NotFound - attributes_in_database" from Pano#_update_document — dozens per second during 22:10-22:25 window

시간 분석:

  • 총 소요: 4292.55ms
  • DB 시간: 253.68ms (5.9%)
  • View 렌더링: 0.09ms
  • 미설명 시간: ~4039ms (94.1%) → S3 HEAD + 프로세스 큐잉 지연

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 호스트 과부하 + S3 HEAD 요청 지연 결합 동일 호스트에서 초당 50건+ Pano 요청 처리 중; DB 시간 253ms로 총 시간의 6%만 차지; 다른 호스트에서 동일 엔드포인트 286ms 정상 응답 Confirmed
H2 N+1 쿼리 또는 DB 병목 DB 시간 253ms로 정상보다 높음 (20ms vs 253ms) 총 시간의 6%에 불과; 로그에 반복 쿼리 패턴 없음; 내부 trace에 DB 관련 로그 2건만 확인 Rejected
H3 외부 서비스 타임아웃 (S3 외) 미설명 시간 4초 존재 S3 외 외부 호출 코드 경로에 없음; 에러/타임아웃 로그 없음; HTTP 200 정상 응답 Rejected
H4 코드 레벨 성능 버그 (serializer 중복 호출 등) serializer에서 presigned URL 생성 2회 발생 presigned URL은 네트워크 호출 없이 로컬 서명만 수행 (수 ms); 정상 요청에서도 동일 경로 실행되나 286ms 소요 Rejected

Fix Recommendation#

즉시 조치 (Critical)#

  • 없음. 단발성 사건(1회)으로 즉각 대응 불필요.

단기 개선 (1주 이내)#

  • app/models/concerns/grid_system.rb:28grid_system_object.exists? 호출에 timeout 설정 추가. AWS SDK의 :http_open_timeout:http_read_timeout을 2초로 제한하여, S3 지연 시 빠르게 실패하도록 변경.
  • app/controllers/concerns/grid_system_controller.rb — S3 호출 결과를 짧은 TTL(10초)로 캐싱하여 반복 호출 방지 검토.

장기 개선 (재발 방지)#

  • 호스트 단위 요청 큐잉 모니터링 추가 — 특정 인스턴스에 요청이 집중될 때 조기 감지.
  • S3 존재 확인을 비동기 패턴(background job + callback)으로 전환 검토. 클라이언트가 업로드 완료 후 S3 Event Notification을 통해 상태를 업데이트하면 HEAD 요청 자체가 불필요.
  • ALB의 least-outstanding-requests 라우팅 알고리즘 검토로 과부하 호스트 회피.

Monitoring#

  • Datadog APM에서 해당 resource의 p95/p99 latency 알림 설정:
text
avg(last_5m):p95:trace.rack.request{service:cupixworks-api, resource_name:api::v1::bimscontroller#check_grid_system_uploading} > 2000
  • 호스트별 요청 큐잉 시간 모니터링:
text
avg(last_5m):avg:trace.rack.request.queue_time{service:cupixworks-api} by {host} > 1000

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial — 단발성 사건으로 코드 변경 없이도 재발 가능성 낮음. S3 timeout 설정은 방어적 개선 수준.