S3 bucket not found — nonexistent hosting bucket reference
RCA: flush_geo_coordinate - The specified bucket does not exist
Error Log#
flush_geo_coordinate - error - message: The specified bucket does not exist
Impact#
- Service:
cupixworks-worker - 발생 횟수: 30
- 최초 발생: 2026-04-06T08:06:29.694Z
- 최근 발생: 2026-04-07T07:06:28.984Z
Root Cause Summary#
ap-northeast-1 리전에 배포된 cupixworks-worker의 cron job이 매 시간 Record ID 1에 대해 flush_geo_coordinate를 실행하고 있으나, 해당 Record의 storage_option에 저장된 S3 hosting bucket이 실제로 존재하지 않는 bucket을 가리키고 있습니다. Record ID 1은 시스템 초기에 생성된 레코드로, fresh_state가 stale 또는 refreshing 상태에 머물러 있어 매 시간 flush_refreshing_records/flush_stale_records cron에 의해 반복적으로 flush 대상에 포함됩니다. flush 시 geo_coordinate_s3_object가 storage_option.s3_hosting_bucket_name으로 S3 upload을 시도하지만, 해당 bucket이 AWS에 존재하지 않아 Aws::S3::Errors::NoSuchBucket 예외가 발생하고, rescue 블록에서 에러 로그를 남기며 실패합니다. flush가 실패하면 fresh_fresh_state! (line 89)에 도달하지 못해 fresh_state가 stale/refreshing에서 벗어나지 못하고, 다음 cron 주기에 다시 대상이 되는 무한 반복 구조입니다.
Technical Analysis#
Code Path#
- Entry point:
config/schedule.rb:82- 매 시간:06에Cupix::Cron::Record.flush_refreshing_records실행 - Cron handler:
lib/cupix/cron/record.rb:12-14-flush_refreshing_records가refreshing_over_hourscope의 모든 Record에 대해flush_geo_coordinate호출
# lib/cupix/cron/record.rb:12-14
def flush_refreshing_records
::Record.refreshing_over_hour.each(&:flush_geo_coordinate)
end
- Scope 정의:
app/models/concerns/fresh_state.rb:14-fresh_state가refreshing이고fresh_state_updated_at이 1시간 이전인 Record를 선택
# app/models/concerns/fresh_state.rb:14
scope :refreshing_over_hour, -> { where(fresh_state: :refreshing).where('fresh_state_updated_at < ?', 1.hour.ago).or(where(fresh_state_updated_at: nil)).untrashed }
- Flush 실행:
app/models/concerns/record_geo_coordinate.rb:37-97-flush_geo_coordinate메서드가 S3에 JSON을 upload
# app/models/concerns/record_geo_coordinate.rb:45-48
geo_coordinate_s3_object.upload_stream(
content_type: 'application/json',
cache_control: "max-age=#{1.year.to_i}",
acl: 'bucket-owner-full-control'
) do |write_stream|
- S3 Object 생성:
app/models/concerns/record_geo_coordinate.rb:103-108-storage_option.s3_hosting_bucket_name을 bucket으로 사용
# app/models/concerns/record_geo_coordinate.rb:103-108
def geo_coordinate_s3_object
Cupix::StorageService.object(
storage_option: storage_option,
bucket_name: storage_option.s3_hosting_bucket_name,
key: s3_object_key
)
end
- Failure point:
app/models/concerns/record_geo_coordinate.rb:45-upload_stream호출 시 AWS S3 SDK가NoSuchBucket에러를 raise
# app/models/concerns/record_geo_coordinate.rb:90-94
rescue StandardError => e
unlock_flushing_geo_coordinate
Cupix::Logger.error("flush_geo_coordinate - error - message: #{e.message}", class: self.class.name, function: __method__, module: 'RecordGeoCoordinate', record: { id: self.id })
false
- 기대 동작:
flush_geo_coordinate가 성공하면 line 89에서fresh_fresh_state!를 호출하여fresh_state를fresh로 전환, 이후 cron 대상에서 제외됨 - 실제 동작: S3 bucket이 존재하지 않아 line 45에서 예외 발생 → rescue 블록(line 90)으로 이동 →
fresh_state가 변경되지 않음 → 다음 cron 주기에 다시 대상이 됨
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-worker status:error "flush_geo_coordinate" "The specified bucket does not exist"
모든 에러 로그가 동일한 패턴을 보입니다. 매 시간 :06 분에 발생하며, 일부 시간대에는 :07 분에 추가 에러가 발생합니다 (:07 분 에러는 4시간 주기의 flush_stale_records cron에 해당):
2026-04-07 16:06:28 KST - flush_geo_coordinate - error - message: The specified bucket does not exist
2026-04-07 15:06:24 KST - flush_geo_coordinate - error - message: The specified bucket does not exist
2026-04-07 14:06:20 KST - flush_geo_coordinate - error - message: The specified bucket does not exist
2026-04-07 13:07:16 KST - flush_geo_coordinate - error - message: The specified bucket does not exist
2026-04-07 13:06:20 KST - flush_geo_coordinate - error - message: The specified bucket does not exist
2026-04-07 12:06:28 KST - flush_geo_coordinate - error - message: The specified bucket does not exist
...
2026-04-06 17:07:23 KST - flush_geo_coordinate - error - message: The specified bucket does not exist
2026-04-06 17:06:29 KST - flush_geo_coordinate - error - message: The specified bucket does not exist
Raw JSON 로그에서 확인한 핵심 정보:
{
"message": "flush_geo_coordinate - error - message: The specified bucket does not exist",
"class": "Record",
"function": "flush_geo_coordinate",
"module": "RecordGeoCoordinate",
"record": { "id": 1 },
"host": { "name": "ip-10-1-80-188.ap-northeast-1.compute.internal" },
"environment": "production",
"service_role": "worker"
}
핵심 관찰:
- Record ID가 항상 1 - 모든 에러가 Record ID 1에서 발생
- 호스트가
ap-northeast-1리전 - 일본 리전 worker에서만 발생 - 매 시간 반복 - cron schedule
'6 * * * *'(flush_refreshing_records)와'7 */4 * * *'(flush_stale_records)에 의해 반복 실행 ap-northeast-1리전의 storage config (config/storage-ap-northeast-1.yaml)에는 production 환경에cupixworks-hosting-*패턴의 bucket만 정의되어 있으나, Record ID 1은 시스템 초기 생성 레코드로 구(legacy) 패턴의s3_hosting_bucket_name을sys[:storage_option]에 가지고 있을 가능성이 높음 - 해당 bucket은ap-northeast-1리전에 프로비저닝되지 않았거나 이미 삭제됨
Fix Recommendation#
즉시 조치 (Critical)#
- Record ID 1의
sys컬럼에서storage_option의s3_hosting_bucket_name값을 확인하고, 실제 존재하는 bucket으로 수정하거나, 해당 Record가 더 이상 사용되지 않는 경우fresh_state를fresh로 전환하여 cron 대상에서 제외 - 확인 방법: Rails console에서
Record.find(1).storage_option.s3_hosting_bucket_name실행하여 현재 bucket 이름 확인 후 AWS console에서 해당 bucket 존재 여부 검증
단기 개선 (1주 이내)#
app/models/concerns/record_geo_coordinate.rb:90-94의 rescue 블록에서NoSuchBucket에러를 별도 처리하여, bucket 미존재 시 무한 재시도를 방지하는 로직 추가 (예: 특정 횟수 이상 실패 시fresh_state를fresh로 전환하거나 별도 알림 발송)lib/cupix/cron/record.rb의flush_stale_records/flush_refreshing_records에서 실패한 Record를 추적하는 로깅 추가
장기 개선 (재발 방지)#
- Storage migration 시 모든 Record의
sys[:storage_option]이 유효한 bucket을 가리키는지 검증하는 스크립트 추가 flush_geo_coordinate실패 시 일정 횟수 이상 반복 실패하면 자동으로 cron 대상에서 제외하는 circuit breaker 패턴 도입ap-northeast-1리전 배포 시 legacy Record의 storage option 호환성 검증 프로세스 정립
Monitoring#
- 추가할 메트릭:
flush_geo_coordinate실패율을 Record ID별로 추적 - Datadog 쿼리 예시:
service:cupixworks-worker "flush_geo_coordinate - error" | stats count by @record.id
NoSuchBucket에러가 동일 Record에 대해 24시간 이상 반복될 경우 알림 설정
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial
- 영향 범위: Record ID 1만 영향받으며, 실제 사용자 데이터에 대한 영향은 없음 (시스템 초기 생성 레코드). 다만, 매 시간 불필요한 에러 로그가 발생하여 노이즈를 유발하고, cron job의 에러 집계를 왜곡할 수 있음