왜 내 배치는 로컬 JobParameter로 실행됐을까?
신규 배치 잡을 개발하면서, 로컬에서 먼저 실행해 정상 동작을 확인한 뒤 개발 서버에 배포해 실행해보았다.그런데 이상한 문제가 발생했다.배치 실행 시 항상 로컬에서 사용했던 JobParameter로만 실행되는 것.Jenkins에서 jobParameter를 넘겨 실행해도, 스프링 배치는 계속 로컬에서 실행한 JobParameter를 고정해서 사용했다.새로 만든 잡에서는 동일 JobParameter로도 배치를 반복 실행할 수 있도록 RunIdIncrementer를 사용한다.이 incrementer는 run.id를 자동으로 증가시켜 새로운 JobInstance를 만들 수 있게 해주는 기능이다.그런데 RunIdIncrementer로 인해 run.id는 정상적으로 1, 2, 3… 증가하는데,정작 내가 설정한 jobParameter가 아니라 로컬에서 실행한 파라미터만 계속 적용되고 있었다.그래서 원인을 제대로 파악해 보기로 했다.RunIdIncrementer는 정확히 무엇을 할까?스프링 소스코드를 보면 역할은 매우 단순하다.public JobParameters getNext(@Nullable JobParameters parameters) { JobParameters params = (parameters == null) ? new JobParameters() : parameters; JobParameter<?> runIdParameter = params.getParameters().get(this.key); long id = 1; if (runIdParameter != null) { id = Long.parseLong(runIdParameter.getValue().toString()) + 1; } return new JobParametersBuilder(params).addLong(this.key, id).toJobParameters(); } 즉:기존 JobParameter에서 run.id가 있으면 +1없으면 1그 외 나머지 JobParameter는 건드리지 않고 그대로 사용즉, RunIdIncrementer는 오직 run.id만 증가시키고그 외 파라미터는 건드리지 않는다.그럼 “그 외 파라미터”는 어디서 오는 걸까?JobParametersBuilder.getNextJobParameters스프링은 다음과 같은 순서로 JobParameter를 만든다.JobInstance lastInstance = jobExplorer.getLastJobInstance(name); JobExecution previousExecution = jobExplorer.getLastJobExecution(lastInstance); nextParameters = incrementer.getNext(previousExecution.getJobParameters()); ... nextParametersMap.putAll(this.parameterMap); // 현재 실행 파라미터 우선 요약하면:이전에 실행한 동일 Job의 JobParameter를 조회한다.RunIdIncrementer로 run.id를 증가시킨 nextParameters를 만든다.이번 실행에서 전달한 jobParameter를 맨 마지막에 merge한다. (가장 높은 우선순위)즉 스프링 배치의 JobParameter 우선순위는 다음과 같다.Spring Batch JobParameter 우선순위이전 실행의 JobParameterIncrementer(getNext) 결과이번 실행 시 전달된 JobParameter (최우선)그렇다면 이번 실행에서 넘겨준 파라미터가 최우선인데 왜 적용되지 않았던 걸까? 전달되지 않을 것 같아 배치 실행 부분을 살펴봤다.문제의 진짜 원인: Jenkins → Docker 실행 시 파라미터가 전달되지 않음스프링 배치 로직상으로는 “이번 실행 파라미터가 가장 우선순위”가 맞다.그런데 실제로 Jenkins에서 JobParameter를 넘겨줘도 실행 결과에는 반영되지 않았다.조사해보니:Jenkins가 전달한 jobParameter를 Dockerfile 내부에서 배치를 실행할 때 넘겨주지 않고 있었다.즉,Jenkins → Docker run → Spring Boot이 체인을 따라 파라미터가 전달되지 않아서스프링은 “이번 실행 파라미터 없음”그럼 당연히 이전 JobParameter를 그대로 가져다 씀incrementer는 run.id만 증가결과적으로 run.id만 달라지고 나머지는 로컬 실행 때의 파라미터가 계속 유지됨그래서 Dockerfile을 수정해 Jenkins에서 받은 파라미터를 그대로 전달해 실행하도록 수정했고문제는 바로 해결되었다.결론1) RunIdIncrementer는 run.id만 올려주는 단순한 기능이다.다른 파라미터는 절대 건드리지 않는다.2) Spring Batch는 이전 실행의 JobParameter를 기본값으로 사용한다.그리고 incrementer를 적용한 뒤,이번 실행 파라미터를 merge한다.3) 이번 실행의 JobParameter가 적용되지 않은 이유는Dockerfile에서 파라미터를 누락해서 전달되지 않았기 때문.4) 따라서 Jenkins → Docker → Spring Boot 실행 구조를 사용할 때는반드시 jobParameter 전달 경로를 점검해야 한다.