Failed to save partial JSON ElementTrace 102272260
RCA: Failed to save partial JSON ElementTrace 102272260
Overview#
What Happened#
2026-05-22 20:20 UTC부터 약 4시간 동안 us-west-2 리전의 cupixworks-worker 호스트 ip-10-1-18-233에서 디스크 공간 부족(No space left on device)으로 인해 partial JSON 파일 저장이 전면 실패했다. ElementTrace를 포함한 4개 모델(ElementTrace, Pointcloud, Capture, Editing)에서 총 719,410건의 에러가 발생했으며, 데이터 웨어하우스로의 변경 데이터 전파가 완전히 중단되었다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | Errno::ENOSPC |
| exception.message | No space left on device @ rb_sysopen - /var/data_changes/element_traces/partial/2026-05-22/uswe2/{timestamp}-element_traces-{id}.json.gz |
| top_frame | app/models/concerns/data_ware_house/partial_json.rb:144 |
| runtime | Ruby 3.3.0, Rails 7.2.2, Sidekiq 7.3.9 |
| deploy | production-us-west-2-20260519T0920Z0-3e770a15-cupixworks |
| env | production, us-west-2 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| Data Warehouse (ElementTrace) | ~719,000 | 변경 데이터 파일 미생성 → downstream 동기화 누락 |
| Data Warehouse (Pointcloud) | 수백 건 | Pointcloud 변경 이력 누락 |
| Data Warehouse (Capture/Editing) | 수십 건 | Capture/Editing 변경 이력 누락 |
Timeline#
- 2026-05-22 20:20:42 UTC — 최초 에러 발생 (ElementTrace 102272260, host ip-10-1-18-233)
- 2026-05-22 20:59:52 UTC — Pointcloud 모델에서도 동일 에러 확인
- 2026-05-22 23:57:59 UTC — 클러스터 내 마지막 에러 기록
- 2026-05-23 00:29:51 UTC — 날짜 변경 후 디렉토리 생성조차 실패 (
dir_s_mkdir에러) - 2026-05-26 — Error Sweeper에 의한 RCA 수행
Error Log#
Failed to save partial JSON ElementTrace 102272260
Impact#
- Service:
cupixworks-worker - 발생 횟수: 719,410
- 최초 발생: 2026-05-22T20:20:42.030Z
- 최근 발생: 2026-05-22T23:57:59.494Z
Root Cause Summary#
호스트 ip-10-1-18-233.us-west-2.compute.internal의 /var/data_changes/ 파티션이 완전히 소진되어 Errno::ENOSPC (No space left on device) 예외가 발생했다. Sidekiq worker들이 partial JSON 파일을 디스크에 기록하려 할 때 파일 오픈(rb_sysopen) 또는 디렉토리 생성(dir_s_mkdir)이 불가능해졌고, 해당 에러가 rescue 블록에서 로깅만 되고 정상 리턴되면서 719,410건의 데이터 변경 이력이 소실되었다. 디스크 공간 관리(cleanup/rotation)가 부재하거나 데이터 축적 속도가 정리 속도를 초과한 것이 근본 원인이다.
Technical Analysis#
Code Path#
- Entry point:
BulkSavePartialJsonToFileWorker#perform(app/workers/bulk_save_partial_json_to_file_worker.rb:71) - Iteration: 배치 단위(50개)로 모델을 순회하며 각각
save_partial_json_to_file호출 - Core save:
partial_json.rb:115—generate_and_save_partial_json - Failure point:
partial_json.rb:144—File.open(filepath, 'wb')에서Errno::ENOSPC발생
Worker에서 배치 처리:
models.find_in_batches(batch_size: 50) do |groups|
groups.each do |model|
model.save_partial_json_to_file(all_data: true, operation: operation, timestamp: timestamp)
end
end
Partial JSON 파일 저장 메서드:
def save_partial_json_file(content, path)
filepath = Rails.env.development? ? "./tmp/storage/#{path}" : "/var/data_changes/#{path}"
create_directory_if_not_exists(filepath)
# Verify directory is writable before attempting file write
dirname = File.dirname(filepath)
unless File.writable?(dirname)
# ... writability check and EACCES raise ...
end
File.open(filepath, 'wb') { |file| file.write(content) }
rescue Errno::EACCES, Errno::ENOSPC => e
Cupix::Logger.error("Failed to save Partial JSON #{self.class.name} #{self.id} to file #{filepath}",
class: self.class.name, module: 'DataWareHouse', function: 'save_partial_json_file',
error: e.message, backtrace: e.backtrace)
end
기대 동작: File.open(filepath, 'wb')로 gzip 압축된 JSON 데이터를 /var/data_changes/ 하위에 저장하고, downstream 시스템이 이를 읽어 데이터 웨어하우스에 동기화.
실제 동작: 디스크 공간 부족으로 File.open이 Errno::ENOSPC를 발생시키고, rescue 블록에서 에러를 로깅한 뒤 정상 리턴. Worker 자체는 실패하지 않으나(retry: false) 데이터 파일이 생성되지 않아 변경 이력이 소실됨.
Bulk 호출 경로 (Repository):
bulk_save_changes_to_partial_json(_model_ids.compact)
def bulk_save_changes_to_partial_json(model_ids = [])
BulkSavePartialJsonToFileWorker.perform_async(self.class.current_class.name, model_ids)
end
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-worker status:error @environment:production "Failed to save partial JSON ElementTrace"
service:cupixworks-worker status:error @environment:production "Failed to save Partial JSON" "No space left on device"
대표 에러 로그 (ElementTrace 102272260 — 최초 발생):
{
"message": "Failed to save partial JSON ElementTrace 102272260",
"error": "No space left on device @ rb_sysopen - /var/data_changes/element_traces/partial/2026-05-22/uswe2/1779481227864174-element_traces-102272260.json.gz",
"host": "ip-10-1-18-233.us-west-2.compute.internal",
"pid": 3114827,
"function": "bulk_partial_save_to_file",
"class": "ElementTrace",
"module": "DataWareHouse",
"timestamp": "2026-05-22T20:20:42.030Z"
}
날짜 변경 후 디렉토리 생성 실패 (2026-05-23):
No space left on device @ dir_s_mkdir - /var/data_changes/element_traces/partial/2026-05-23
Stack trace:
/usr/lib64/ruby/3.3.0/fileutils.rb:402:in `mkdir'
/var/app/current/app/models/concerns/data_ware_house/base.rb:28:in `create_directory_if_not_exists'
/var/app/current/app/models/concerns/data_ware_house/partial_json.rb:176:in `save_partial_json_file'
/var/app/current/app/models/concerns/data_ware_house/partial_json.rb:171:in `generate_and_save_partial_json'
/var/app/current/app/models/concerns/data_ware_house/partial_json.rb:71:in `save_partial_json_to_file'
/var/app/current/app/workers/bulk_save_partial_json_to_file_worker.rb:73:in `block (2 levels) in perform'
Pointcloud 에러 (20:59 UTC):
{
"message": "Failed to save Partial JSON Pointcloud 1103638 to file /var/data_changes/pointclouds/partial/2026-05-22/uswe2/1779483593397961-pointclouds-1103638.json.gz",
"error": "No space left on device @ rb_sysopen - /var/data_changes/pointclouds/partial/2026-05-22/uswe2/1779483593397961-pointclouds-1103638.json.gz",
"host": "ip-10-1-18-233.us-west-2.compute.internal",
"function": "save_partial_json_file",
"class": "Pointcloud",
"timestamp": "2026-05-22T20:59:54.252Z"
}
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | /var/data_changes/ 파티션 디스크 공간 소진 |
모든 에러가 Errno::ENOSPC ("No space left on device")이며, 단일 호스트 ip-10-1-18-233에서만 발생. rb_sysopen과 dir_s_mkdir 모두 동일 원인. 4개 모델 클래스 전부 동일 에러. |
— | Confirmed |
| H2 | 파일 권한(Permission) 문제 | 코드에 Errno::EACCES 처리 존재, 이전 TSLA-12288에서 권한 문제 수정 이력 있음 |
로그 메시지가 모두 ENOSPC이며 EACCES 에러는 없음. 권한 체크 통과 후 파일 오픈에서 실패. |
Rejected |
| H3 | 특정 ElementTrace ID의 데이터 이상으로 인한 쓰기 실패 | ElementTrace 102272260이 최초 에러 | Pointcloud, Capture, Editing 등 모든 모델에서 동일 에러 발생. ID와 무관하게 모든 쓰기 실패. | Rejected |
| H4 | Sidekiq worker 버그 (batch 처리 로직 오류) | Worker가 retry: false로 재시도하지 않음 |
Worker 코드 자체는 정상 동작. rescue 블록이 ENOSPC를 잡아 로깅하는 것은 의도된 동작. 문제는 인프라(디스크)에 있음. | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
- 호스트
ip-10-1-18-233의/var/data_changes/디스크 사용량 확인 및 오래된 partial JSON 파일 정리 - 디스크 공간 확보 후 에러가 자연 해소되었는지 확인
- 에러 발생 기간(4시간) 동안 누락된 변경 이력에 대한 full sync 수행 필요 여부 검토
단기 개선 (1주 이내)#
/var/data_changes/디렉토리에 대한 자동 정리(cleanup) cronjob 추가: 일정 기간(예: 7일) 이상 된 partial JSON 파일 삭제- 디스크 사용률 임계값(80%, 90%) 알림 설정으로 사전 감지
save_partial_json_file에서 ENOSPC 발생 시 circuit breaker 또는 rate limiting 도입 검토: 현재는 모든 건마다 개별 에러 로그를 남겨 719K건의 중복 로그 발생
장기 개선 (재발 방지)#
- Partial JSON 파일을 로컬 디스크 대신 S3에 직접 스트리밍하는 방식으로 아키텍처 변경 검토 (디스크 의존도 제거)
- 또는 EBS 볼륨 자동 확장(autoscaling) 설정
- 디스크 풀 상태에서의 데이터 소실 방지를 위한 재처리 메커니즘 도입: 현재
retry: false이므로 ENOSPC로 실패한 작업은 영구 소실됨
Monitoring#
/var/data_changes/파티션 디스크 사용률 모니터링 (80% 경고, 90% 긴급)- ENOSPC 에러 발생 빈도 알림 (1분 내 10건 이상 시 즉시 알림)
service:cupixworks-worker status:error "No space left on device" @environment:production
system.disk.in_use{host:ip-10-1-18-233.us-west-2.compute.internal,device:/var/data_changes} > 0.9
Risk Assessment#
- Risk level: high
- 예상 복잡도: standard (디스크 정리는 즉시 가능, 구조적 개선은 아키텍처 변경 필요)