Errno::ENOSPC: No space left on device @ dir_s_mkdir - /var/data_changes/meta_change/element_traces/partial/2025-08-19/u
RCA: Errno::ENOSPC @ dir_s_mkdir - /var/data_changes/meta_change/element_traces/partial
Overview#
What Happened#
tesla 의 Data Warehouse CDC (change-data-capture) 경로가 변경 데이터를 gzip JSON 으로 /var/data_changes/<model>/partial/<date>/<region>/ 아래에 저장한다. 이 볼륨(worker 인스턴스의 전용 EBS)이 가득 차면 partition 디렉터리를 만드는 FileUtils.mkdir_p 가 Errno::ENOSPC (No space left on device) 로 실패한다. Representative Error 는 dir_s_mkdir — 즉 write 가 아니라 디렉터리 생성 단계의 ENOSPC 다. 이 정확한 증상(mkdir ENOSPC)은 이미 Airbrake #7565 로 근본 분석되어 TSLA-12956 (PR 88061) 에서 graceful degrade 로 수정되었으며, 현재 develop 에는 병합되어 있으나 master(production) 에는 아직 배포되지 않았다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | Errno::ENOSPC |
| exception.message | No space left on device @ dir_s_mkdir - /var/data_changes/meta_change/element_traces/partial/2025-08-19/uswe2/1755618510791938-meta_change |
| top_frame | app/models/concerns/data_ware_house/partial_json.rb:25 (FileUtils.mkdir_p) / app/models/concerns/data_ware_house/base.rb:28 |
| runtime | Ruby on Rails (tesla), Sidekiq worker (SavePartialJsonToFileWorker) |
| deploy | fix d4b44f30f (TSLA-12956) merged to develop, NOT in master |
| env | production, region uswe2 (us-west-2) — worker instance role |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| cupixworks-api / cupixworks-worker (Data Warehouse CDC) | 2107 (Error Tracking 누적) | CDC partial JSON 일부 유실 가능 — datalake 동기화에 해당 변경분 누락. 사용자 대면 API 응답에는 영향 없음 (after_commit 비동기 경로). |
Timeline#
- 2025-08-20 00:48 KST — 최초 발생 (
first_seen2025-08-19T15:48:29Z UTC). partition2025-08-19/uswe2의meta_changemkdir 이 ENOSPC. - 2026-05-23 (KST) — Airbrake #7565:
/var/data_changes/elements/partial/2026-05-23mkdir ENOSPC 광역 발생, 별도 조사 트리거. - 2026-06-10 10:10 KST — TSLA-12956 (PR 88061)
develop병합 (d4b44f30f): mkdir ENOSPC/EDQUOT 를 raise 대신 로그 + metric 으로 degrade. - 2026-08-02 10:48 KST — Error Tracking
last_seen(2026-08-02T01:48:51Z UTC). 단, 해당 시각 전후 Datadog 로그에는 매칭 결과 0건 (아래 Log Evidence). - 2026-08-04 (오늘) — RCA.
develop에 fix 존재하나master미배포 상태 확인.
Error Log#
No space left on device @ dir_s_mkdir - /var/data_changes/meta_change/element_traces/partial/2025-08-19/uswe2/1755618510791938-meta_change
Impact#
- Service:
cupixworks-api(실제 write 는cupixworks-worker/teslarepo) - 발생 횟수: 2107 (Error Tracking 누적, 2025-08-19 ~ 2026-08-02)
- 최초 발생: 2025-08-20 00:48 KST
- 최근 발생: 2026-08-02 10:48 KST (Error Tracking
last_seen— 단 Datadog 로그 미확인, stale 가능성)
Root Cause Summary#
/var/data_changes 는 worker 인스턴스의 전용 EBS 볼륨(81_mount_volume.sh)으로, Data Warehouse CDC 가 모든 모델 변경분을 gzip JSON 으로 <model>/partial/<date>/<region>/ 파티션에 append 한다. 일일 정리 cron(delete_old_data_changes.sh, 매일 02:00, 1일 이전 파티션 삭제)이 유입량을 따라가지 못하거나 하루치 write 량이 볼륨 용량을 초과하면 볼륨이 가득 차 Errno::ENOSPC 가 발생한다. Representative Error 는 dir_s_mkdir 단계 — 파티션 디렉터리를 만드는 FileUtils.mkdir_p 에서의 ENOSPC 다. 기존 코드는 File.open write 단계의 ENOSPC 만 rescue 하고 mkdir_p ENOSPC 는 그대로 raise 하여 Error Tracking 에 잡혔다. 이 증상은 이미 TSLA-12956 (PR 88061) 에서 stage:mkdir metric + error log 로 graceful degrade 하도록 수정되어 develop 에 병합되었으나, master(production) 에는 아직 배포되지 않았다. 즉 근본 원인은 (1) 디스크 용량/정리 cadence 라는 인프라 조건 이고, (2) 그 코드-side 핸들링(더 이상 raise 하지 않도록) 은 이미 fix 되어 release 대기 중 이다.
Technical Analysis#
Code Path#
- Entry point: 모델
after_commit→SavePartialJsonToFileWorker또는bulk_partial_save_to_file(Sidekiq worker) - CDC write 대상 디렉터리 생성:
base_dir = Rails.env.development? ? './tmp/storage' : '/var/data_changes'
target_dir = "#{base_dir}/#{pluralized_model_name}/partial/#{partition_date}/#{region}"
FileUtils.mkdir_p(target_dir) unless File.directory?(target_dir)
- Failure point:
partial_json.rb:25의FileUtils.mkdir_p(그리고 동일 패턴base.rb:28의create_directory_if_not_exists). 이mkdir_p는 아래rescue블록 밖에 있다.
ids.each_with_index do |id, idx|
# ...
json_content = ActiveSupport::Gzip.compress(json_data.to_json)
filepath = "#{target_dir}/#{timestamp}-#{pluralized_model_name}-#{id}.json.gz"
File.open(filepath, 'wb') { |file| file.write(json_content) }
rescue Errno::EACCES, Errno::ENOSPC => e
Cupix::Logger.error("Failed to save partial JSON #{self.name} #{id}", class: self.name, function: __method__, error: e.message)
end
def create_directory_if_not_exists(filepath)
dirname = File.dirname(filepath)
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
end
-
기대 동작 vs 실제 동작:
rescue Errno::ENOSPC는File.openwrite 실패만 흡수한다. 볼륨이 가득 찬 상태에서는 파티션 디렉터리 생성mkdir_p(dir_s_mkdir시스템 콜) 자체가 먼저 ENOSPC 로 실패하고, 이 예외는 rescue 되지 않아 worker/after_commit 밖으로 전파되어 Error Tracking 에dir_s_mkdir로 기록된다. -
인프라 경로 (실제 근본 원인 조건):
if mountpoint -q /var/data_changes; then
echo "EBS volume is already mounted at /var/data_changes"
exit 0
fi
# Get the reference date (1 days ago) in YYYY-MM-DD format
reference_date=$(date --date="1 days ago" '+%Y-%m-%d')
# ...
base_dir="/var/data_changes"
-
정리 cron 은 매일 02:00 실행되어 1일 이전 partition 을 삭제하지만, 하루치 CDC write 량이 EBS 용량을 넘거나 cron 실패 시 볼륨이 포화된다.
-
이미 반영된 fix (develop, master 미배포):
Merged PR 88061: TSLA-12956 fix: degrade gracefully on ENOSPC in data_ware_house partial JSON / CSV writers- Airbrake #7565: /var/data_changes/elements/partial/2026-05-23 mkdir ENOSPC.- 기존 bulk writer 는 File.open ENOSPC 만 rescue 하고 mkdir_p ENOSPC 는 raise 했다.- mkdir ENOSPC/EDQUOT 는 raise 대신 stage:mkdir metric + error log 로 처리.Log Evidence#
Error Tracking last_seen (2026-08-02) 전후를 포함한 최근 14일 Datadog 로그 검색 결과, 어떤 변형으로도 매칭 로그가 0건 이다. Representative Error 는 2025-08-19 파티션의 stale sample 이며, Error Tracking 이 여러 variant 를 하나로 묶어 오래된 메시지를 pin 한 것으로 보인다.
service:cupixworks-api "No space left on device" → Found 0 logs (now-14d)
service:cupixworks-api "Errno::ENOSPC" → Found 0 logs (now-14d)
service:cupixworks-api "dir_s_mkdir" → Found 0 logs (now-14d)
service:cupixworks-api "data_changes" → Found 0 logs (now-14d)
service:cupixworks-worker "No space left on device"→ Found 0 logs (now-14d)
service:cupixworks-worker "data_changes" → Found 50 logs (모두 정상 cron)
data_changes 하위 시스템 자체는 정상 동작 중 — cron 은 처리 대기 항목이 0건이다:
{
"timestamp": "2026-08-04 17:22:31",
"status": "info",
"message": "[Cron][Sidekiq] data_changes has items: 0"
}
즉 최근 14일 동안 production 에서 이 ENOSPC 가 로그로 확인된 재발은 없으며, data_changes CDC 파이프라인 자체는 건강하다. Error Tracking 의 last_seen 은 로그로 shipping 된 실제 occurrence 와 일치하지 않는다 (stale).
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | /var/data_changes EBS 볼륨 포화로 mkdir_p 가 ENOSPC — 디스크 용량/정리 cadence 인프라 조건 |
Representative dir_s_mkdir = 디렉터리 생성 ENOSPC; 81_mount_volume.sh 로 전용 EBS 확인; delete_old_data_changes.sh 1일 정리 cron; TSLA-12956 배경이 동일 증상(Airbrake #7565) 명시 |
— | Confirmed |
| H2 | 코드 로직 결함(nil/조건 오류)으로 인한 예외 | — | 예외는 OS-level Errno::ENOSPC; 코드 흐름은 정상, write 대상만 없음 |
Rejected |
| H3 | mkdir ENOSPC 를 rescue 하지 않는 코드 버그가 현재 tree 에 남아 있음 | 구 코드는 File.open 만 rescue, mkdir_p 는 raise (partial_json.rb:25 rescue 밖) |
TSLA-12956 (d4b44f30f) 이 develop 에서 mkdir ENOSPC 를 graceful degrade 로 이미 수정 — git merge-base --is-ancestor d4b44f30f origin/develop = true |
Rejected (fix 존재, release 대기) |
| H4 | 최근 대량 재발 중인 active 버그 | Error Tracking last_seen 2026-08-02 |
최근 14일 Datadog 로그 0건; status board active: null; data_changes cron items: 0 정상 |
Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
- 코드 변경 불필요. 문제의 코드-side 핸들링(
mkdirENOSPC graceful degrade)은 이미 TSLA-12956 (PR 88061, commitd4b44f30f) 로develop에 병합됨.git merge-base --is-ancestor d4b44f30f origin/master= false — 즉 다음 production 배포에서 자동 해소된다. 새 PR/worktree 를 만들지 말 것 (release-pending duplicate). - 인프라 측면: 현재 최근 14일 재발 로그가 없으므로 즉시 볼륨 조치는 불필요. 재발 시
/var/data_changesEBS 용량 확장 또는delete_old_data_changes.sh실행/성공 여부(cron 로그) 점검이 1차 대응.
단기 개선 (1주 이내)#
- TSLA-12956 이 포함된 릴리즈를
master로 배포하여 mkdir ENOSPC 가 Error Tracking 이 아닌stage:mkdirmetric + error log 로 degrade 되도록 함. 배포 후 Error Tracking issue 는 신규 occurrence 없이 자동 stale → resolve 되어야 한다. - 정리 cron 관측성 확보:
delete_old_data_changes.sh성공/삭제량을 Datadog 로 shipping 하여 정리 실패를 조기 탐지.
장기 개선 (재발 방지)#
/var/data_changes볼륨 free-space 를 host metric 으로 모니터링하고 임계(예: 80%) 알람 설정 — write 실패보다 앞서 감지.- CDC partial 을 로컬 디스크 대신 S3 직접 write 로 전환하거나, 파티션 정리 주기를 write 량에 맞춰 동적으로 조정하여 단일 EBS 용량 의존을 제거.
Monitoring#
배포 후 재발 여부를 timeseries 로 관측:
sum:trace.rack.request.errors{service:cupixworks-worker,error.type:Errno::ENOSPC}.as_count()
정리 cron 및 CDC 파이프라인 건강도 (info 로그 count):
sum:logs.count{service:cupixworks-worker,@message:*data_changes*}.as_count()
TSLA-12956 배포 후 신규 metric (fix 코드가 emit) 관측:
sum:tesla.data_warehouse_partial_json_failed.count{stage:mkdir}.as_count()
Risk Assessment#
- Risk level: low (사용자 대면 영향 없음, 코드 fix 이미 존재, 최근 재발 로그 0건)
- 예상 복잡도: trivial (배포 cadence 문제 — 신규 코드 작업 불필요)
Noise Verdict#
noise — 디스크 포화(ENOSPC)라는 인프라 조건이고, mkdir ENOSPC 를 graceful degrade 하는 코드 fix(TSLA-12956)가 이미 develop 에 병합되어 다음 릴리즈 배포만 남았으며 최근 14일 재발 로그도 없다.