error on starting sitetrack on record_id: 6277 - Updating entity on billing expired team/workspace i
RCA: error on starting sitetrack on record_id: 6277 - Updating entity on billing expired team/workspace
Overview#
What Happened#
2026-04-30 19:47~19:53 UTC 사이에 cupixworks-api (eu-central-1)에서 Editing 상태 전환 후 자동 sitetrack 생성이 2회 실패했다. Team "spen" (id: 62)의 billing이 만료된 상태에서 capture processing이 완료되어 sitetrack 생성이 트리거되었으나, BaseFactory#check_updatable_by_billing_state!에서 PERM33000 에러로 거부되었다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | Cupix::Errors::PermissionDenied |
| exception.message | Updating entity on billing expired team/workspace is not allowed |
| top_frame | lib/cupix/abstract/base.rb:38 |
| deploy | production-eu-central-1-20260430T1710Z0-768ef1f7-cupixworks |
| env | production, eu-central-1 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| spen (id: 62) | 2 | Sitetrack 자동 생성 실패 — 사용자가 수동으로 재시도해도 billing 만료로 인해 동일 실패 발생 |
Timeline#
- 2026-04-30T19:47:05Z — Capture 33627, 33628, 33629 processing 완료,
[Record] applied_license: expired on 6277로그 - 2026-04-30T19:47:11Z — Editing done 전환 →
_perform_sitetrack_start→ SitetrackFactory 생성 시도 → PERM33000 에러 (1차) - 2026-04-30T19:53:23Z — Capture 33630 processing 완료, billing 만료 확인
- 2026-04-30T19:53:25Z — 동일 flow 재실행 → PERM33000 에러 (2차)
Error Log#
error on starting sitetrack on record_id: 6277 - Updating entity on billing expired team/workspace is not allowed
Impact#
- Service:
cupixworks-api - 발생 횟수: 2
- 최초 발생: 2026-04-30T19:47:11.582Z
- 최근 발생: 2026-04-30T19:53:25.736Z
Root Cause Summary#
Team "spen" (id: 62)의 billing이 만료된 상태에서 capture processing이 완료되면 Editing 상태가 done으로 전환되고, after_transition hook이 자동으로 start_sitetrack을 호출한다. 이 과정에서 SitetrackFactory#create! → BaseFactory#create! → check_updatable_by_billing_state!가 실행되는데, Sitetrack 모델의 applied_billing_state가 'expired'를 반환하므로 PERM33000 에러가 발생한다. 문제의 핵심은 billing 상태를 사전 검증하지 않고 sitetrack 생성을 시도하는 것이다. _perform_sitetrack_start는 editing 유효성, 기존 sitetrack 존재 여부, video capture 존재 여부는 체크하지만 billing 상태는 체크하지 않는다.
Technical Analysis#
Code Path#
- Entry point:
app/models/concerns/statable/editing.rb:159-161—after_transition to: :donehook
after_transition from: any, to: :done do |model, transition|
model.start_sitetrack
end
start_sitetrack(line 226)에서 facility 조건 검증 후_perform_sitetrack_start호출 (line 255)
if sitetrack_startable
Cupix::Logger.info("All conditions met. Calling StartSitetrackWorker for Editing #{self.id}", class_name: self.class.name, function: __method__)
_perform_sitetrack_start
end
_perform_sitetrack_start(line 262)에서 기본 검증 수행 후SitetrackFactory.create!호출 (line 301)
Cupix::Logger.info("start sitetrack on record_id: #{self.record_id}", class: self.class.name, function: __method__, record: { id: self.record_id }, level_id: self.level_id)
begin
sitetrack = ::SitetrackFactory.new(current_user: self.user, current_team: self.team).create!({
record_id: self.record_id,
level_id: self.level_id
})
Cupix::Logger.info("Sitetrack automatically created for record_id: #{self.record_id}, level_id: #{self.level_id}, sitetrack_id: #{sitetrack.id}", class: self.class.name, function: __method__, record: { id: self.record_id }, level_id: self.level_id, sitetrack: { id: sitetrack.id })
rescue StandardError => e
Cupix::Logger.error("error on starting sitetrack on record_id: #{self.record_id} - #{e.message}", class: self.class.name, function: __method__, record: { id: self.record_id }, level_id: self.level_id)
return
end
SitetrackFactory#create!(line 5-37)에서 모델 초기화 후super→BaseFactory#create!호출
def create!(params = {})
self.model = ::Sitetrack.new(team_id: self.current_team.id)
- Failure point:
BaseFactory#create!line 84 →check_updatable_by_billing_state!
def create!(params = {})
raise Cupix::Errors::Unauthorized.new(code: 'ARG10000', reason: 'current_user is required') if self.current_user.nil? && current_user_required?
check_archived_entity
check_updatable_by_billing_state!
- 실제 billing 검증 로직에서
applied_billing_state == 'expired'조건에 해당되어 예외 발생
if self.model.applied_billing_state == 'expired'
raise Cupix::Errors::PermissionDenied.new(code: 'PERM33000', reason: 'Updating entity on billing expired team/workspace is not allowed')
end
- Sitetrack 모델은
FacilityEntity→FacilityEntity::Billing을 include하여 team/workspace/facility billing 상태를 종합 판단
def applied_billing_state
billing_states = [team_billing_state, workspace_billing_state, facility_billing_state]
return 'active' if billing_states.include?('active')
return 'expired' if billing_states.include?('expired')
'none'
end
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-api status:error @environment:production "error on starting sitetrack on record_id: 6277"
service:cupixworks-api @environment:production "6277"
에러 발생 직전 로그 시퀀스 (1차, 19:47:11Z):
[INFO] Capture 33627 processing is completed. record_id:6277 (class: Capture, function: notify_processing_completed)
[INFO] skipped to push processing_completed notification for record:6277. skip_reason: unfinalized capture exists (unfinalized: [33627, 33629, 33630])
[INFO] Capture 33629 processing is completed. record_id:6277
[INFO] [Record] applied_license: expired on 6277
[INFO] start sitetrack on record_id: 6277 (class: Editing, function: _perform_sitetrack_start)
[ERROR] error on starting sitetrack on record_id: 6277 - Updating entity on billing expired team/workspace is not allowed
에러 발생 직전 로그 시퀀스 (2차, 19:53:25Z):
[INFO] Capture 33630 processing is completed. record_id:6277 (class: Capture, function: notify_processing_completed)
[ERROR] skipped to push processing_completed notification by Billing has expired on Team for record:6277 (error_code: BILL6000)
[INFO] [Record] applied_license: expired on 6277
[INFO] start sitetrack on record_id: 6277 (class: Editing, function: _perform_sitetrack_start)
[ERROR] error on starting sitetrack on record_id: 6277 - Updating entity on billing expired team/workspace is not allowed
핵심 관찰: [Record] applied_license: expired on 6277 로그가 매번 에러 직전에 출력되어 billing 만료 상태가 이미 감지되고 있음에도 sitetrack 생성 시도가 진행됨.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | Billing 만료 상태에서 sitetrack 자동 생성 시도 시 사전 검증 부재 | _perform_sitetrack_start에 billing 체크 없음 (editing.rb:262-314). 로그에서 applied_license: expired 확인 후에도 생성 시도 진행. BaseFactory에서 PERM33000 발생 |
— | Confirmed |
| H2 | Billing 상태가 일시적으로 잘못 계산됨 (race condition) | — | 동일 record에 대해 시간 간격(6분)을 두고 2회 동일 에러 발생. 로그에서 일관되게 expired 상태 보고. 사용자 API 호출(GET /records/6277)도 정상 200 반환하여 read는 허용됨 |
Rejected |
| H3 | Capture processing 완료 이벤트가 잘못된 타이밍에 발생 | Capture 33627-33630이 짧은 시간 내 완료되어 여러 번 트리거됨 | Editing done 전환은 정상적 flow이며, 각 capture 완료 시 editing이 done으로 전환될 수 있음. 타이밍이 아닌 billing 상태가 문제 | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
- 파일:
app/models/concerns/statable/editing.rb:262(_perform_sitetrack_start메서드) - 방향: Sitetrack 생성 시도 전에 billing 상태를 먼저 확인하여,
expired인 경우 info 레벨로 로깅하고 조기 return. 이는 예상 가능한 비즈니스 시나리오이므로 error 레벨 로그가 아닌 info 또는 warn으로 처리해야 한다.
단기 개선 (1주 이내)#
start_sitetrack메서드(line 226)의sitetrack_startable조건에 billing 상태 검증을 추가하여_perform_sitetrack_start진입 전에 차단. 이렇게 하면 불필요한 DB 쿼리(existing sitetrack 조회, video captures 조회)도 방지할 수 있다.
장기 개선 (재발 방지)#
- Capture processing 완료 → Editing done 전환 → sitetrack 생성 파이프라인 전체에서 billing 만료 팀의 자동 처리를 일관되게 스킵하는 정책 수립.
notify_processing_completed에서는 이미 BILL6000으로 차단하고 있으므로, sitetrack 생성도 동일 패턴을 따르도록 통일.
Monitoring#
추가할 메트릭/알림:
service:cupixworks-api status:error "error on starting sitetrack" "billing expired"
- Billing 만료 팀에서의 sitetrack 생성 시도 빈도를 추적하는 custom metric 추가 고려
- 현재 발생 빈도(2회)가 낮으므로 즉각적 알림보다는 주간 리포트에 포함하는 수준이 적절
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial