BulkableRepository missing .compact on nil IDs
RCA: Workarea with ids [nil, nil, nil, nil, nil, nil] does not match after 6 retries
Error Log#
Workarea with ids [nil, nil, nil, nil, nil, nil] does not match after 6 retries
Impact#
- Service:
cupixworks-worker - 발생 횟수: 1 (이 클러스터 기준), Datadog 14일 기간 동안 총 30건 발생
- 최초 발생: 2026-04-14T04:28:05.584Z
- 최근 발생: 2026-04-14T04:28:05.584Z
Root Cause Summary#
Workarea bulk update/delete 작업에서 일부 또는 전체 항목이 실패하면, BulkableRepository가 실패한 항목의 ID를 nil로 대체한 후 .compact를 호출하지 않고 BulkSavePartialJsonToFileWorker에 전달합니다. Worker는 nil ID 배열로 Workarea.where(id: [nil, nil, ...]) 쿼리를 실행하여 항상 0건을 반환하고, 6회 재시도 후 에러를 기록합니다. 이 문제를 수정한 커밋(ae00552f1, TSLA-12264)이 develop 브랜치에는 존재하지만 master 브랜치(프로덕션 배포 대상)에 머지되지 않아 수정이 프로덕션에 반영되지 않았습니다.
Technical Analysis#
Code Path#
- Entry point:
BulkableRepository#bulk!(app/repositories/concerns/bulkable_repository.rb:5) - Workarea mixin:
BulkableRepository::Workarea(app/repositories/concerns/bulkable_repository/workarea.rb:1) - Failure point:
BulkSavePartialJsonToFileWorker#perform(app/workers/bulk_save_partial_json_to_file_worker.rb:50-66)
1단계: Bulk 작업에서 invalid items 발생
BulkableRepository#bulk!에서 update/delete 작업 중 에러가 발생하면 해당 항목이 _invalid_items에 추가됩니다:
# app/repositories/concerns/bulkable_repository.rb:30-46 (update case)
_models.each_with_index do |model, index|
_repository = self.class.new(review: _review, current_user: current_user, model: model, parent: _parent)
_item = params[:items].find { |x| x[:id] == model.id }
next if _item.nil?
# ... update operations ...
_repository.update(_item.except(:id))
rescue StandardError => e
_invalid_items << {
index: index
}.merge(Cupix::Util::ErrorParser.parse_error(e))
next
end
2단계: Nil ID 주입 및 worker 호출 (문제 지점)
실패한 항목의 인덱스에 nil을 설정한 후, 프로덕션 master 브랜치에서는 .compact 없이 worker에 전달합니다:
# app/repositories/concerns/bulkable_repository.rb:69-71 (master 브랜치 — 현재 프로덕션)
_invalid_items.each { |invalid_item| _model_ids[invalid_item[:index]] = nil }
bulk_save_changes_to_partial_json(_model_ids) # .compact 없음 — nil이 포함된 배열 전달
develop 브랜치에는 수정이 존재합니다:
# app/repositories/concerns/bulkable_repository.rb:71 (develop 브랜치 — 미배포)
bulk_save_changes_to_partial_json(_model_ids.compact) # .compact 추가
3단계: Worker에서 nil ID로 쿼리 실패
프로덕션 master 브랜치의 worker에는 nil guard가 없어, nil이 포함된 ids로 쿼리를 실행합니다:
# app/workers/bulk_save_partial_json_to_file_worker.rb:7-8 (master 브랜치 — 현재 프로덕션)
def perform(class_name, ids = [], options_json = {})
# nil guard 없음 — ids가 그대로 사용됨
Workarea.where(id: [nil, nil, nil, nil, nil, nil])은 항상 0건을 반환하므로 models.count (0) != ids.count (6) 조건에 걸려 6회 재시도 후 에러가 기록됩니다:
# app/workers/bulk_save_partial_json_to_file_worker.rb:50-68 (프로덕션 코드)
$MAX_RETRIES.times do |retries|
models = model_class.where(id: ids) # nil ID로 쿼리 → 항상 0건
if models.count != ids.count # 0 != 6 → 항상 true
delay = 0.1 * (2**retries)
Cupix::Logger.warn("Retry #{retries + 1} - #{class_name} with ids #{ids} count does not match, retrying in #{delay} seconds", ...)
sleep(delay)
next
else
break
end
end
if models.count != ids.count
Cupix::Logger.error("#{class_name} with ids #{ids} does not match after #{$MAX_RETRIES} retries", ...)
return false
end
4단계: 수정이 프로덕션에 미배포
TSLA-12264 커밋(ae00552f1, 2026-03-24)이 .compact 추가와 worker nil guard를 포함하지만, develop에만 존재하고 master에 머지되지 않았습니다:
$ git merge-base --is-ancestor ae00552f1 remotes/origin/master
→ NOT ancestor (fix NOT in master)
$ git branch -a --contains ae00552f1 | grep -E "develop|master"
→ * develop
→ (master not listed)
Log Evidence#
Datadog 검색 쿼리:
service:cupixworks-worker status:error "Workarea with ids" @environment:production
2026-04-14 에러 타임라인 (request_id: 68c8c0c1847f13ae4c3cee09):
| Timestamp (UTC) | Level | Message |
|---|---|---|
| 04:27:59.582Z | warn | Retry 1 - Workarea with ids [nil, nil, nil, nil, nil, nil] count does not match, retrying in 0.1 seconds |
| 04:27:59.582Z | warn | Retry 2 - Workarea with ids [nil, nil, nil, nil, nil, nil] count does not match, retrying in 0.2 seconds |
| 04:27:59.582Z | warn | Retry 3 - Workarea with ids [nil, nil, nil, nil, nil, nil] count does not match, retrying in 0.4 seconds |
| 04:27:59.582Z | warn | Retry 4 - Workarea with ids [nil, nil, nil, nil, nil, nil] count does not match, retrying in 0.8 seconds |
| 04:28:01.583Z | warn | Retry 5 - Workarea with ids [nil, nil, nil, nil, nil, nil] count does not match, retrying in 1.6 seconds |
| 04:28:03.583Z | warn | Retry 6 - Workarea with ids [nil, nil, nil, nil, nil, nil] count does not match, retrying in 3.2 seconds |
| 04:28:05.584Z | error | Workarea with ids [nil, nil, nil, nil, nil, nil] does not match after 6 retries |
공통 속성:
Class: BulkSavePartialJsonToFileWorker
Function: perform
Host: ip-10-1-19-158.ap-southeast-2.compute.internal
Region: ap-southeast-2
Deploy Version: production-ap-southeast-2-20260411T0127Z0-9e255c3b-cupixworks
14일간 발생 패턴:
- 총 30건의 error 레벨 발생 (2026-03-31 ~ 2026-04-14)
- 주요 영향 리전: ap-southeast-2 (대부분), us-west-2 (1건)
- nil 배열 크기 다양: 1~8개 — bulk 작업의 실패 항목 수에 따라 변동
- 2026-04-03에 11건 집중 발생
- Worker class는 항상
BulkSavePartialJsonToFileWorker#perform - 모든 경우 exponential backoff 패턴 동일 (0.1s, 0.2s, 0.4s, 0.8s, 1.6s, 3.2s)
Fix Recommendation#
즉시 조치 (Critical)#
TSLA-12264 커밋을 master 브랜치에 머지하여 프로덕션에 배포해야 합니다.
이 커밋은 이미 두 곳에서 수정을 포함합니다:
app/repositories/concerns/bulkable_repository.rb:71—.compact추가하여 nil ID 제거app/workers/bulk_save_partial_json_to_file_worker.rb:7-15— nil guard 추가로 빈 ID 배열 조기 반환
수정 코드가 이미 develop에 존재하므로 새로운 코드 작성이 필요 없으며, release 프로세스를 통해 master에 반영하면 됩니다.
단기 개선 (1주 이내)#
BulkableRepository#bulk!에서 모든 항목이 실패한 경우 worker를 아예 호출하지 않는 조건 추가를 검토해야 합니다 (모든 ID가 nil이면_model_ids.compact는 빈 배열이므로 worker 호출이 불필요)BulkableFactory#bulk!의_new_model_ids처리도 동일한 패턴인지 확인 필요 — line 66에서 nil 삽입 후 line 63의.compact가 호출되지만, 순서상.compact가 nil 삽입 이전에 실행되므로 Factory 경로는 영향받지 않음
장기 개선 (재발 방지)#
develop→master머지 프로세스를 점검하여, 버그 수정 커밋이 적시에 프로덕션에 반영되도록 release 파이프라인을 개선해야 합니다BulkSavePartialJsonToFileWorker에 입력 검증을 강화하여 nil ID가 전달되면 조기에 감지하고 로깅하는 방어적 코드 추가 검토
Monitoring#
- 다음 Datadog 쿼리로 수정 배포 후 에러 재발 여부를 모니터링:
service:cupixworks-worker status:error "does not match after" @environment:production
BulkSavePartialJsonToFileWorker의 nil ID 감지를 위한 경고 모니터 설정:
service:cupixworks-worker "no valid IDs provided" @environment:production
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial — 이미 작성된 수정(
TSLA-12264)을master에 머지하고 배포하면 해결됩니다. 에러 자체는 data warehouse의 partial JSON 파일 저장 실패이므로 사용자 기능에 직접적 영향은 없으나, 약 6.3초간 불필요한 sleep으로 worker 리소스가 낭비됩니다.