본문 바로가기

강의/스프링배치

스프링 배치 - JobExecutionDecider

 

flowJob 을 구성할 때

stop on to end를 연결하여 하나의 flow를 연결하였다.

step은 일종의 buisiness 로직을 담는 부분인데

stop on to end와 강한 결합이 생기고

on to end 이런 api가 복잡하게 구성될 수 있다.

 

여러 step을 구성하다보면 전체적인 step을 파악하기가 어렵다.

 

jobExecutionDecider는 Transition 처리를 위한 전용 클래스 이기 때문에

내부적인 로직을 통해 flow 흐름을 제어할 수 있다.

 

훨씬 간단하게 심플하게 구성할 수 있다.

transitional api를 사용하는  보다 더 깔끔하게 구성할 수 있다.

 

 

 

configuration

package io.springbatch.springbatch.jobExecutionDecider;

import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@RequiredArgsConstructor
@Configuration
public class JobExecutionDeciderConfiguration {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job jobExecutionDecider() {
        return jobBuilderFactory.get("jobExecutionDeciderjob")
                .incrementer(new RunIdIncrementer())
                .start(jobExecutionDeciderStep1())
                .next(decider())
                .from(decider()).on("ODD").to(jobExecutionDeciderOddStep())
                .from(decider()).on("EVEN").to(jobExecutionDeciderEvenStep())
                .end()
                .build();
    }

    @Bean
    public JobExecutionDecider decider() {
        return new CustomDecider();
    }

    @Bean
    public Step jobExecutionDeciderStep1() {
        return stepBuilderFactory.get("deciderStep1")
                .tasklet((stepContribution, chunkContext) -> {
                    System.out.println("decider step1 was executed");
                    return RepeatStatus.FINISHED;
                }).build();
    }

    @Bean
    public Step jobExecutionDeciderEvenStep() {
        return stepBuilderFactory.get("evenStep1")
                .tasklet((stepContribution, chunkContext) -> {
                    System.out.println("even step was executed");
                    return RepeatStatus.FINISHED;
                }).build();
    }

    @Bean
    public Step jobExecutionDeciderOddStep() {
        return stepBuilderFactory.get("oddStep1")
                .tasklet((stepContribution, chunkContext) -> {
                    System.out.println("odd step was executed");
                    return RepeatStatus.FINISHED;
                }).build();
    }
}

 

decider

package io.springbatch.springbatch.jobExecutionDecider;

import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.JobExecutionDecider;

public class CustomDecider implements JobExecutionDecider {

    private int count = 0;

    @Override
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {

        count ++;

        if (count % 2 == 0) {
            return new FlowExecutionStatus("EVEN");
        } else {
            return new FlowExecutionStatus("ODD");
        }
    }
}

 

SimpleFlow의 start() 메서드가 호출된다.

res

이후 resume 메서드가 호출된다.

status는 decider를 가지고 있따.

state.handler 하게 되면 customdecider가 호출된다.

decisionStatue는 내부에 decider를 가지고 있고

이때 customDecider가 호출된다.