ES /docs

Missing trashed filter in facility refresh query

RCA: Failed to refresh average cadence on bfbc2l: Calculating average cadence is not supported for trashed facility

Error Log#

Datadog Logs

text
Failed to refresh average cadence on bfbc2l: Calculating average cadence is not supported for trashed facility: bfbc2l

Impact#

  • Service: cupixworks-worker
  • 발생 횟수: 1
  • 최초 발생: 2026-04-10T00:30:46.439Z
  • 최근 발생: 2026-04-10T00:30:46.439Z

Root Cause Summary#

Cupix::Cron::Facility.refresh_average_cadence_on_record_created 크론 잡이 최근 24시간 내 Record가 생성된 facility를 조회할 때 trashed 상태의 facility를 필터링하지 않습니다. 이로 인해 facility bfbc2l이 trashed 상태임에도 refresh_average_cadence! 메서드가 호출되어, 해당 메서드의 trashed facility guard가 Cupix::Errors::Entity 예외를 발생시킵니다. 에러 자체는 rescue로 잡혀 로그에 기록되며 다른 facility의 처리를 중단하지는 않지만, 불필요한 에러 로그를 생성합니다.

Technical Analysis#

Code Path#

  • Entry point: config/schedule.rb:152 — 매일 00:30 UTC에 cron이 refresh_average_cadence_on_record_created를 실행
ruby
# config/schedule.rb:151-153
every '30 0 * * *' do
  runner 'Cupix::Cron::Facility.refresh_average_cadence_on_record_created'
end
  • Step 1: lib/cupix/cron/facility.rb:14-24 — 최근 1일 내 Record가 생성된 facility를 조회하되, trashed 상태를 필터링하지 않음
ruby
# lib/cupix/cron/facility.rb:14-24
def refresh_average_cadence_on_record_created
  facilities = ::Facility.where(id: ::Record.where('created_at > ?', 1.day.ago).pluck(:facility_id))

  Cupix::Logger.info("Refreshing average cadence on #{facilities.count} facilities by record creation")

  facilities.each do |facility|
    facility.refresh_average_cadence!
  rescue StandardError => e
    Cupix::Logger.error("Failed to refresh average cadence on #{facility.key}: #{e.message}")
  end
end
  • Failure point: app/models/concerns/analysis/facility.rb:10-15refresh_average_cadence!가 trashed facility에 대해 예외를 발생시킴
ruby
# app/models/concerns/analysis/facility.rb:9-15
def refresh_average_cadence!
  if trashed?
    raise Cupix::Errors::Entity.new(
      code: 'ENT10000',
      reason: "Calculating average cadence is not supported for trashed facility: #{key}"
    )
  end
  # ...
end

기대 동작: trashed facility는 cadence 갱신 대상에서 제외되어야 합니다. Analysis::Facility concern의 scope인 refresh_cadence_candidates(line 6)는 이미 untrashed 필터를 포함하고 있으나, cron 메서드는 이 scope를 사용하지 않습니다.

ruby
# app/models/concerns/analysis/facility.rb:6
scope :refresh_cadence_candidates, -> { untrashed.where('next_cadence_check_at <= ?', DateTime.now).where(delay_status: false) }

실제 동작: ::Facility.where(id: ...) 쿼리가 trashed 포함 모든 facility를 반환하여, trashed facility bfbc2l에서 예외가 발생합니다.

동일한 문제가 refresh_average_cadence_on_schedule (line 26-36)에도 존재합니다. 해당 메서드도 동일한 패턴으로 trashed facility를 필터링하지 않습니다.

Log Evidence#

1. Facility trash 요청 (원인):

text
service:cupixworks-api "bfbc2l" "trash"
Time: 2026-04-09T00:00:00Z to 2026-04-10T01:00:00Z
json
{
  "timestamp": "2026-04-09T05:41:21.255Z",
  "service": "cupixworks-api",
  "status": "info",
  "message": "[204] PUT /api/v1/facilities/bfbc2l/trash (Api::V1::FacilitiesController#trash)",
  "user": "jhangwon.yoon@cupix.io (user_id: 42295)",
  "team": "qatest3 (id: 1131)"
}

Facility bfbc2l은 에러 발생 약 19시간 전에 trash 처리되었습니다.

2. 크론 배치 실행 로그:

text
service:cupixworks-worker "Refreshing average cadence"
Time: 2026-04-09T23:30:00Z to 2026-04-10T01:00:00Z
json
{
  "timestamp": "2026-04-10T00:30:30.406Z",
  "status": "info",
  "message": "Refreshing average cadence on 152 facilities by record creation",
  "host": "ip-10-1-18-233.us-west-2.compute.internal",
  "pid": 1104873
}

동일 PID(1104873)에서 152개 facility 배치 처리가 시작되었고, 16초 후 bfbc2l에서 에러가 발생했습니다.

3. 에러 로그:

text
service:cupixworks-worker "bfbc2l"
Time: 2026-04-09T23:30:00Z to 2026-04-10T01:00:00Z
json
{
  "timestamp": "2026-04-10T00:30:46.439Z",
  "status": "error",
  "message": "Failed to refresh average cadence on bfbc2l: Calculating average cadence is not supported for trashed facility: bfbc2l",
  "host": "ip-10-1-18-233.us-west-2.compute.internal",
  "pid": 1104873,
  "region": "us-west-2",
  "version": "production-us-west-2-20260410T0030Z0-045f9011-cupixworks"
}

4. 타임라인:

시각 (UTC) 서비스 이벤트
2026-04-09T05:41:21Z cupixworks-api PUT /api/v1/facilities/bfbc2l/trash -> 204 (user: jhangwon.yoon@cupix.io)
2026-04-10T00:30:30Z cupixworks-worker Cron: "Refreshing average cadence on 152 facilities by record creation"
2026-04-10T00:30:44-46Z cupixworks-worker 48+ 성공: "Average cadence has updated on facility: XXX"
2026-04-10T00:30:46Z cupixworks-worker ERROR: "Failed to refresh average cadence on bfbc2l"

5. 14일간 동일 에러 패턴 검색 — 2건 발생:

text
service:cupixworks-worker status:error "Failed to refresh average cadence" "not supported for trashed"
Time: now-14d
시각 환경 Facility
2026-04-10T00:30:46Z production (us-west-2) bfbc2l
2026-04-03T00:30:29Z qa (us-west-2) 32yqde

QA 환경에서도 동일한 패턴이 확인되어, 이는 체계적인 문제(systemic issue)입니다.

Fix Recommendation#

즉시 조치 (Critical)#

  • 파일: lib/cupix/cron/facility.rb:15lib/cupix/cron/facility.rb:27
  • 두 cron 메서드(refresh_average_cadence_on_record_created, refresh_average_cadence_on_schedule)의 facility 쿼리에 .untrashed scope를 추가하여 trashed facility를 제외해야 합니다.
  • 현재: ::Facility.where(id: ::Record.where('created_at > ?', 1.day.ago).pluck(:facility_id))
  • 변경 방향: .untrashed 체인 추가

단기 개선 (1주 이내)#

  • refresh_cadence_candidates scope가 이미 analysis/facility.rb:6에 정의되어 있으므로, cron 메서드에서 이 scope를 활용하는 것을 검토해야 합니다. 다만, 이 scope는 next_cadence_check_atdelay_status 조건도 포함하고 있어 cron의 의도와 다를 수 있으므로 비즈니스 로직 확인이 필요합니다.

장기 개선 (재발 방지)#

  • Facility 관련 batch 작업에서 trashed 상태 필터링을 누락하는 패턴이 반복될 수 있으므로, trashed facility를 자동으로 제외하는 default scope 도입 또는 코드 리뷰 체크리스트에 해당 항목을 추가하는 것을 검토해야 합니다.

Monitoring#

  • 동일 에러 재발 모니터링:
text
service:cupixworks-worker status:error "Failed to refresh average cadence" "not supported for trashed"

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial — .untrashed scope 추가만으로 해결 가능