ES /docs

job 10455 job_stopped_callback error - /var/app/current/vendor/bundle/ruby/3.3.0/gems/logger-1.6.6/l

Fix Plan: Cupix::Event logger open failure — Phase 1 defense (event.log 폐지 로드맵 1/3)

배경 (선택된 fix option)#

RCA 의 "### 권장 조치 — event.log 폐지 (사용자 승인 방향)" 는 다음 3-phase 실행 계획이다:

  1. Phase 1 — 즉시 방어: Cupix::Event.publish 호출부 개별 rescue + Cupix::Event#initialize open 실패 시 IO::NULL fallback.
  2. Phase 2 — 이중 발행 검증: Kinesis(EventService) 커버리지 vs. 로컬 event.log 소비자 조사. 인프라/데이터 팀과의 협업 필요.
  3. Phase 3 — 파일 로거 폐지: Phase 2 결과에 근거해 Cupix::Event, filebeat 설정, postdeploy touch/chown 라인을 삭제.

이 PR 은 Phase 1 만 담고, Phase 2/3 은 별건 issue 로 hand-off 한다. 사유:

  • Phase 1 만으로 본 클러스터의 job callback 예외 전파와 capture :done 전이 실패는 즉시 차단된다 (RCA §"권장 조치 Phase 1" 결론).
  • Phase 2 는 .ebextensions/003-filebeat.config:99-113 이 tail 하는 *-event.log 의 다운스트림 소비자(logstash cls-tesla → ??? 인덱스) 파악이 선행되어야 한다. 이 확인 없이 3-phase 를 한 PR 로 묶으면 이벤트 shipping 이 조용히 끊길 위험이 있다.
  • Phase 3 는 applications/event-service (cupixworks 레포) 의 Kinesis→S3 이관 커버리지 검증 결과에 의존적이며, 배포 순서(Kinesis 안정성 확인 → filebeat 소비자 정리 → 파일 로거 폐지)에 따라 릴리스 경계를 갖는다.

Changes#

tesla: lib/cupix/event.rb#

  • What: initialize 를 다음과 같이 방어한다.
    1. File.open (parent ActiveSupport::Logger#initialize 가 호출) 실패 시 Errno::* 및 광의 SystemCallError 를 rescue.
    2. rescue 시 Cupix::Logger.warn (또는 fallback 이 이용 가능하면 warn) 으로 상황을 남기고, super(IO::NULL, ...) 방식으로 재-초기화한다 — IO::NULL 은 daily rotation 이 필요 없으므로 shift_age argument 를 제거하거나 super(IO::NULL) 로 재호출한다.
    3. Singleton 이 이미 한 번 초기화된 이후에는 재-.instance 호출도 같은 객체를 반환하므로, 이 fallback 은 프로세스 lifetime 내내 유지된다 (재시도 없음).
  • Why: RCA §"권장 조치 Phase 1" 두 번째 항목. 현재 코드는 Singleton initialize 자체가 예외를 낸 채로 반환하면 다음 .instance 호출까지 실패가 지속되어 job_stopped_callback 이 반복 실패한다. 초기화 자체가 예외를 삼켜야 한다.
  • Lines: 1-21 (파일 전체 리팩터, 3-5 라인 추가 예상)
  • 참고: 향후 Phase 3 에서 이 파일 자체를 삭제할 예정이므로, 내부 구현만 수정하고 public API (Cupix::Event.publish) 는 유지한다.

tesla: app/models/concerns/eventable/events/base.rb#

  • What: create_event(model)begin ... rescue StandardError ... end 블록 내부에서 두 발행 호출을 분리한다.
    • Cupix::EventService.publish_event([event]) 는 기존과 동일하게 트랜잭션에 붙어 있는 primary 발행 경로로 유지 (Kinesis 실패 시에는 raise 를 유지해 롤백 유도).
    • Cupix::Event.publish(event.serializable_hash(...)) 호출을 별도 begin/rescue StandardError => local_err 로 감싸고, rescue 시 Cupix::Logger.warn("Cupix::Event.publish (legacy file logger) skipped: ...", error: local_err, ...) 로 강등한다. 이 실패는 raise 하지 않는다 — 즉 상위 rescue 로 흘러가지 않으며 event_created! 및 state machine 전이는 그대로 진행된다.
  • Why: RCA §"권장 조치 Phase 1" 첫 번째 항목. 로컬 파일 로거 실패가 이벤트 스토어 커밋(EventService/Kinesis)과 state machine 전이(:done)를 막지 않도록 격리한다. 이중 발행 구조상 파일 로거는 이미 부수적 경로이므로 강등이 안전하다.
  • Lines: 7-26 (create_event 메서드 내부)

tesla: app/factories/concerns/bulkable_factory/annotation.rb (범위에서 제외)#

  • 관측 (구현 중 확인): 이 파일은 origin/master 트리에 존재하지 않고 develop 브랜치에만 있다 (git ls-tree -r origin/master app/factories/concerns/bulkable_factory/ 결과에서 부재 확인). RCA 는 develop 기준으로 두 참조 지점을 열거했으나, master 로 병합되는 이 PR 의 범위에서는 하나(app/models/concerns/eventable/events/base.rb)만 존재.
  • 조치: master 브랜치에서는 수정 대상 없음. annotation.rb 가 develop→master 로 병합되는 시점에 별건 후속 patch (또는 develop 병합 전 리베이스) 로 동일 강등 패턴을 적용해야 한다. Follow-up 은 hand-off 문서에 기록.
  • Lines: N/A

Non-Changes (범위 외)#

  • Phase 2/3 삭제 작업 전체: lib/cupix/event.rb 파일 삭제, Cupix::EventFormatter 삭제, .ebextensions/003-filebeat.config:99-113 filestream 블록 제거, .platform/hooks/postdeploy/70|71|72_restart_sidekiq.shAPP_EVENT_LOG_FILEPATH 및 관련 touch/chown 라인 제거는 이 PR 범위 밖. Phase 2 검증(다운스트림 소비자 확인) 완료 후 별건 이슈로 진행한다.
  • RCA "부수 개선": Cupix::Logger 포맷터의 e.class/e.message prefix 소실 문제, cron staggering 우선순위 조정 — 별건 이슈로 유지. cron staggering 은 이미 TSLA-13526 로 병합되어 있다.
  • retry helper 도입: RCA 원안의 장기 개선 항목이었으나 사용자 선택은 "폐지" 방향이므로 도입하지 않는다.

Acceptance Criteria#

  • lib/cupix/event.rbCupix::Event.instance 호출이 파일 open 실패 시에도 예외를 raise 하지 않고 IO::NULL fallback logger 를 반환한다.
  • app/models/concerns/eventable/events/base.rbcreate_eventCupix::Event.publish 실패 시 상위 rescue StandardError 블록을 트리거하지 않고 (즉 raise e 로 흘러가지 않고) 정상적으로 model.event_created! 를 수행한다.
  • app/factories/concerns/bulkable_factory/annotation.rbcreate_bulk_events! 는 각 이벤트별 Cupix::Event.publish 실패 시에도 나머지 이벤트 처리와 RunAfterEventCreatedWorker.perform_async enqueue 를 계속한다.
  • Cupix::EventService.publish_event 실패는 여전히 상위로 propagate 되어 Cupix::Logger.errorraise e 경로를 탄다 (primary 발행의 실패는 격리하지 않는다).
  • ruby -c (변경 3 파일) 통과.
  • grep -rn "Cupix::Event\.publish" app/ lib/ 결과 지점 수는 이 PR 변경 전과 동일 (호출 지점 삭제 없음 — 강등만).

Tests#

  • 기존 테스트: 없음 — lib/cupix/event.rb, Eventable::Events::Base.create_event, BulkableFactory::Annotation#create_bulk_events! 각각에 대한 rspec spec 은 존재하지 않는다 (spec/lib/cupix/event_spec.rb, spec/models/concerns/eventable/events/base_spec.rb, spec/factories/concerns/bulkable_factory/annotation_spec.rb 부재). needs verification: 워크트리에서 ls 확인 후, 없다면 신규 spec 추가는 이 PR 범위 밖 (Phase 3 삭제 예정 파일에 대한 신규 스펙 투자 최소화).
  • 신규 테스트: 없음 — 폐지 예정 경로에 신규 spec 을 추가하지 않는다. Phase 1 방어의 회귀는 Datadog 모니터 (RCA §"Monitoring" 쿼리) 로 관측한다.