Skip to content

파싱 워커가 JVM 치명 오류를 정상 실패로 삼키지 않는다 - #947

Merged
m-a-king merged 1 commit into
devfrom
fix/941-error-propagation
Aug 15, 2026
Merged

파싱 워커가 JVM 치명 오류를 정상 실패로 삼키지 않는다#947
m-a-king merged 1 commit into
devfrom
fix/941-error-propagation

Conversation

@m-a-king

Copy link
Copy Markdown
Collaborator

Situation

  • 파싱 워커는 추출·전이·정체성 기록·원본 회수를 전부 runCatching 으로 감싼다. Kotlin 의 runCatchingException 이 아니라 Throwable 을 잡으므로 JVM 치명 오류까지 삼킨다.
  • Error 는 "이 요청이 실패했다"가 아니라 "이 프로세스로는 더 진행할 수 없다" 는 신호다. 그 신호를 받아 처리하는 층은 이미 바깥에 있다: JVM 의 -XX:+ExitOnOutOfMemoryError, 컨테이너 재시작, 배포의 헬스체크와 blue-green 전환. 워커가 삼키면 그 층들이 아무것도 하지 못한다.
  • 게다가 두 워커는 재시도 불가 예외를 확정 실패로 분류해 종결하는데, 이미지 경로에서 확정 실패는 원본 이미지 회수(삭제) 를 동반한다. 서버 사정으로 죽는 순간 사용자가 올린 원본까지 지워져 재실행할 입력이 사라진다.

Task

  • 치명 오류를 우리 실패 원장에 적지 않고 바깥으로 흘려보낸다.
  • 되돌아가기 쉬운 변경이라(한 곳만 runCatching 으로 바꿔도 그 자리에서 다시 샌다) 회귀를 기계가 막게 한다.

Action

포획 범위 좁히기

Exception 만 잡는 runCatchingException 을 만들고 두 워커의 runCatching 10곳을 전부 교체했다.

처음에는 추출 호출만 바꾸려 했으나, 확인해 보니 전이·정체성 기록·원본 삭제까지 같은 문제를 갖고 있었다. Error 는 어느 지점에서 나든 전파돼야 한다는 원칙이 일관되게 서도록 전부 교체했다. 반환 타입을 Result 로 맞춰 기존 onSuccess/onFailure 체인은 그대로이고 포획 범위만 좁아진다.

재시도 판정에서 Error 분기를 제거했다. 이제 도달할 수 없는 분기인데, 남기면 다음 사람이 "여기로 Error 가 온다"고 읽어 삼키는 설계로 되돌리기 쉽다.

전파의 실제 도달점 (실측)

모든 Error 가 프로세스를 죽이지는 않는다. 과장하지 않으려고 실측해 주석에 남겼다.

오류 어디까지 가나
힙 OOM JVM 이 스스로 종료 (ExitOnOutOfMemoryError). 워커에 도달조차 안 함
그 외 Error @Async 라 Spring 의 async 예외 핸들러까지. 커스텀 핸들러가 없어 기본 구현이 ERROR 로그를 남김

핵심 이득은 프로세스 종료가 아니라 확정 실패로 오분류되지 않는 것이다. 그 덕에 상태 전이·원본 회수·메트릭 오염이 사라지고, 행은 처리중으로 남아 stale 회수가 되살린다. 박동 레지스트리는 guardedfinallyError 가 지나가도 정리하는 것을 확인했다.

회귀 막기

포획 경계를 테스트로 못 박았다. Exception 은 실패 결과로, Error 3종(OutOfMemoryError·StackOverflowError·NoClassDefFoundError)은 그대로 전파.

여기에 두 워커가 표준 runCatching 을 쓰면 실패하는 검사를 더했다. 한 곳만 되돌아가도 그 자리에서 조용히 새는데 리뷰로만 걸러야 하는 종류라, 기계 판정이 가능한 불변식을 결정론 층으로 내렸다. 주석에 이름이 등장하는 것은 위반으로 세지 않는다.

기존 기대 두 곳(재시도 판정의 Error 케이스, 사유 집계의 OutOfMemoryError 케이스)은 더 이상 성립하지 않아 제거하고 이유를 주석에 남겼다.

Result

  • 치명 오류가 파싱 실패로 위장되지 않는다. 이미지 경로에서 원본이 지워지지 않아 재실행 입력이 보존된다.
  • 회귀 검사가 실제로 작동하는지 확인했다: 추출 호출 하나를 표준 runCatching 으로 되돌려 검사가 잡는 것을 보고 원복했다.
  • 긴급도는 낮다. 30일 실측상 실제 OOM 발생은 0건이고, 힙 OOM 은 JVM 플래그가 먼저 종료시켜 워커에 도달하지 않는다. 이 PR 이 닫는 것은 StackOverflowError 등 다른 Error 가 열어둔 경로와, 안전이 코드가 아니라 배포 워크플로의 JVM 플래그에 걸려 있던 구조다. 누군가 메모리 설정을 손보며 그 플래그를 빼면 위험이 조용히 부활하는데, 이제 코드가 스스로 막는다.
  • 이슈 본문의 초기 서술(발생 이력 159건, 높은 긴급도)은 오독이었어서 실측으로 정정해 두었다. 그 159건은 전부 JVM 기동 배너로, 플래그 이름에 OutOfMemoryError 문자열이 들어 있어 로그 검색에 걸린 것이다.

연관 이슈

@m-a-king m-a-king added the fix 외부 가시적 결함 수정 label Aug 15, 2026
@m-a-king m-a-king self-assigned this Aug 15, 2026
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: de2f6cf8-5739-406f-bb5d-2e9b2f9b3727


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

Discord 스레드 연동용 메타데이터입니다. discord-pr-bot 워크플로가 자동 생성하며, 수정·삭제하면 PR 과 Discord 알림 연동이 끊깁니다.

@m-a-king
m-a-king merged commit 2a8fd36 into dev Aug 15, 2026
8 checks passed
@m-a-king
m-a-king deleted the fix/941-error-propagation branch August 15, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix 외부 가시적 결함 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[fix] 파싱 워커가 JVM 치명 오류(Error)를 정상 실패로 삼키지 않게 한다

1 participant