강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

덕덕님의 프로필 이미지
덕덕

작성한 질문수

죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.

1장. 작전2: 잡 파라미터와 스프링 배치 Scope (파라미터 없는 배치? 그건 그냥 좀비 프로세스나 마찬가지다 ☠️)

Spring Batch 4.3.10 ExecutionContext 한글 인코딩 이슈 관련 문의

작성

·

54

·

수정됨

1

안녕하세요, 강사님.

강의와 직접적인 내용은 아니지만, 사내에서 발생한 Spring Batch 오류와 관련해 조언을 구하고자 문의드립니다.
혹시 시간이 괜찮으시다면 의견을 주시면 정말 감사하겠습니다.

 

1. 사용 환경

  • Java 1.8

  • Spring Boot 2.7.18

  • Spring Batch 4.3.10

     

 

2. 문제 상황

Spring Batch의 ExecutionContext에 한글 문자열을 저장한 이후,
다음 배치 실행 시 아래와 같은 오류가 발생하며 Job이 지속적으로 실패하는 현상이 있었습니다.

java.lang.IllegalArgumentException: Unable to deserialize the execution context
 at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow
~
Caused by: com.fasterxml.jackson.core.JsonParseException: Invalid UTF-8 start byte 0xb2

해당 Job은 chunk 기반 배치이며, 마지막 close() 시점에
다음 Step에서 사용할 정보를 ExecutionContext에 저장하고 있었습니다.
이때 ResultMsg: "정상 처리" 와 같이 한글 문자열을 저장한 이후부터 문제가 발생했습니다.

 

3. 원인 분석

  • IDE(Eclipse) 인코딩: UTF-8

  • DB 인코딩: NLS_CHARACTERSET = KO16MSWIN949

BATCH_JOB_EXECUTION_CONTEXT 테이블에 데이터가 저장되는 구조로 확인했습니다.

  • SHORT_CONTEXT (VARCHAR2(2500))

  • SERIALIZED_CONTEXT (CLOB)

     

2500byte 이하의 데이터는 SHORT_CONTEXT에 저장되는데,
해당 컬럼이 MS949 기반 VARCHAR2이다 보니
UTF-8 기반으로 직렬화된 ExecutionContext 내 한글 데이터가 깨지면서
다음 실행 시 역직렬화 실패가 발생한 것으로 판단했습니다.

 

4. 고민 중인 해결 방안

현재 아래와 같은 방안들을 검토 중입니다.

  1. ExecutionContext에 한글 자체를 사용하지 않도록 제한

    • 로깅/메시지 성 데이터는 저장하지 않거나, 필요 시 영문만 사용

  2. ExecutionContext에 putString 시 인코딩 설정

  3. ExecutionContext 직렬화 방식 변경

    • ExecutionContextSerializer를 DefaultExecutionContextSerializer 명시정으로 설정

    • (Spring Batch 4는 기본적으로 JacksonExecutionContextStringSerializer)

 

5. 질문

강사님께서 보시기에 위 상황에서 가장 권장되는 해결 방향 또는 실무적으로 안전한 접근 방식은 무엇이라고 생각하시는지 궁금합니다.

긴 글 읽어주셔서 감사드리며, 가능하실 때 조언 주시면 많은 도움이 될 것 같습니다.

감사합니다.

답변 2

1

KILL-9님의 프로필 이미지
KILL-9
지식공유자

반갑다 덕덕형 💀

=====================================================================
:: EMERGENCY RESPONSE :: ENCODING MALFUNCTION DETECTED
=====================================================================
보고서 ID: INF-BATCH-ENC-001
발신: KILL-9
수신: 덕덕
분류: ExecutionContext UTF-8/MS949 충돌
=====================================================================

[ 상황 분석 ]

한글로 저장하면 저런 문제가 있었군. 나도 처음본 이슈이다 💀

=====================================================================

[ 전술적 대응 방안 분석 ]

먼저 핵심 질문 하나.

"ExecutionContext에 한글을 반드시 저장해야 하는가?"


---

[시나리오 1: 한글 저장이 필수가 아닌 경우]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
권장 전술: 한글 사용 제거
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

가장 간단하고 안전한 방법이다.

질의자가 제시한 예시:
ResultMsg: "정상 처리"

이것은 로깅/메시지성 데이터로 보인다.
ExecutionContext의 주 목적은 "재시작을 위한 상태 저장"이다.
로깅 메시지나 상태값을 여기 넣을 이유가 있을까?

대안
1. BatchStatus / ExitStatus 활용
   - Spring Batch가 제공하는 표준 상태 체계
   
2. 필요시 영문 메시지로 대체
   - "NORMAL_PROCESSING", "SUCCESS", "COMPLETED" 등

장점:
✅ 인코딩 이슈 원천 차단
✅ 시스템 복잡도 증가 없음
✅ 추가 설정 불필요

---

[시나리오 2: 한글 저장이 필수인 경우]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
권장 전술: DefaultExecutionContextSerializer로 변경
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
=====================================================================
[END OF TRANSMISSION]
[CLEARANCE: RESTRICTED]
=====================================================================
덕덕님의 프로필 이미지
덕덕
질문자

안녕하세요~ 바쁘실텐데 아침부터 답변 주셔서 정말 감사합니다!!

 

ExecutionContext 주 목적이 재시작을 위한 상태값이긴 한데.. 편의성을 위해서 넣어두고 후처리로 DB에 로깅을 할려고 했습니다ㅠㅠ

 

혹시 한글 저장이 필수일 때 시나리오 2: DefaultExecutionContextSerializer로 사내 솔루션 변경이 불가능하다면 하단 방법도 고려해볼만 한가요?

 

  1. 별도 예외 주머니인 JobContexHolder 세팅 후 예외 발생 시 jobContextHolder.set(e.toString); 후 사용

     

    @Component
    @JobScope
    public class JobContextHolder {
        private String errorMessage;
    } 
  2. 따로 주머니에 담지 않고 JobExecutionListener의 afterJob 메서드에서 jobExcecution.getAllFailureExceptions(); 사용

     

    import org.apache.commons.lang.exception.ExceptionsUtils;
    
    @JobScope
    @Component
    public class CustomErrorJobExecutionListener implements JobExecutionListener {
       
       @Override
       public void beforeJob(JobExecution jobExecution) {
          // ~ 생략
       }
    
       @Ovveride
       public void afterJob(JobExecution jobExecution) {
          if (BatchStatus.FAILED == jobExecution.getStatus()) {
             // ~ null 체크 생략
             String firstFullTrace = ExceptionUtils.getStackTrace(jobExecution.getAllFailureExceptions.get(0);
             // firstFullTrace를 DB INSERT
          }
       }
    }

 

2가지 방안중에 2안이 좋을 것 같긴합니다.

혹시 다른 방법도 있을까요??

KILL-9님의 프로필 이미지
KILL-9
지식공유자

아하 2번이 더 좋아 보이는군 

잘 알고있겠지만 BATCH_JOB_EXECUTION 테이블에 EXIT_MESSAGE라는 칼럼에도 실패를 발생시킨 스택트레이스 정보가 저장되니 참고하도록 하라  💀💀


덕덕님의 프로필 이미지
덕덕
질문자

바쁘실텐데 감사합니다~~

0

안녕하세요, 인프런 AI 인턴입니다.

덕덕님, Spring Batch에서 한글 인코딩 문제로 인해 어려움을 겪고 계시는군요. 이 문제는 일반적으로 데이터베이스와 애플리케이션 간의 인코딩 불일치에서 발생할 수 있는 문제로 보입니다. 특히, ExecutionContext에 한글을 저장할 때, 인코딩에 주의해야 합니다.

원인 분석 및 해결 방안

  1. 인코딩 불일치 문제 확인:

    • 우선, 애플리케이션이 사용하는 모든 부분의 인코딩 설정을 확인해 보세요. IDE, 데이터베이스, 애플리케이션(java source flags 포함)까지 모두 UTF-8로 통일되어 있는지 점검합니다.
  2. 한글 사용 제한:

    • 말씀하신 첫 번째 방안처럼 ExecutionContext에서 한글 사용을 가급적 피하는 것이 가장 안전한 방법입니다. 이 방법은 인코딩 문제를 근본적으로 회피하는 방법이 됩니다.
    • 중요한 저장 데이터는 영문이나 코드화된 형태로 저장하고, 필수적일 때만 한글을 사용하도록 하는 것이 좋습니다.
  3. 직렬화 방식 변경:

    • ExecutionContextSerializerJackson2ExecutionContextStringSerializer로 변경하는 방법은 직렬화된 데이터의 인코딩을 명시적으로 제어하기 때문에 유용할 수 있습니다. 이 방법은 ExecutionContext의 직렬화 과정에서 인코딩 문제를 해결해 줄 수 있습니다.
    • 하지만, 이 경우에도 데이터베이스 자체의 문자셋으로 인한 제한은 해결하기 어려울 수 있습니다. 따라서 데이터 전송 시 변환이 필요합니다.
  4. 데이터베이스 설정 변경:

    • 데이터베이스의 NLS_CHARACTERSET을 UTF-8로 변경할 수 있다면, 가장 확실한 해결책이 될 수 있습니다. 다만, 이는 전체적인 데이터베이스 설계에 영향을 주므로 신중히 고려해야 합니다.
    • 특히, 기존 데이터에 영향이 발생할 수 있으므로, 데이터베이스 관리자와 협의가 필요합니다.

추천하는 해결책

가장 안전하고 권장되는 해결방안은 ExecutionContext에 한글을 사용하지 않거나, 데이터베이스 쪽에서 UTF-8로의 형식 변경을 고려하는 것입니다. 특히 장기적으로 봤을 때 인코딩을 통일하는 것이 관리 측면에서도 유리합니다.

이 문제와 관련해 유사한 상황이 있는 다른 게시물도 참고하실 수 있습니다:
- ExecutionContext 인코딩 문제와 해결

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.

현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

덕덕님의 프로필 이미지
덕덕

작성한 질문수

질문하기