Как запустить Spring Batch Jobs в определенном порядке (Spring Boot)?

Я разрабатываю с помощью Spring Batch, используя Spring Boot.

Я с минимальной конфигурацией, предоставляемой Spring Boot, и определил несколько заданий (вообще без конфигурации XML). Но когда я запускаю приложение,

SpringApplication.run(App.class, args);

задания последовательно выполняются в произвольном порядке.

Я определяю работу таким образом в @Configuration аннотированные классы, Spring делает все остальное:

@Bean
public Job requestTickets() {
    return jobBuilderFactory.get(Config.JOB_REQUEST_TICKETS)
            .start(stepRequestTickets())
            .build();
}

Как я могу поручить каркасу запускать задания в определенном порядке?

РЕДАКТИРОВАТЬ: Может ли это предупреждение дать подсказку? (Может быть нечего)

2016-12-29 17:45:33.320  WARN 3528 --- [main] o.s.b.c.c.a.DefaultBatchConfigurer: No datasource was provided...using a Map based JobRepository

5 ответов

Решение

1.Вы сначала отключите автоматический запуск задания, указав spring.batch.job.enabled=false в приложении. свойства

2. В вашем основном классе, сделать - ApplicationContext ctx = SpringApplication.run(SpringBatchMain.class, args); при условии, что ваш главный класс назван - SpringBatchMain.java.

Это будет инициализировать контекст без запуска каких-либо заданий.

3. Как только контекст инициализирован, вы можете сделать: JobLauncher jobLauncher = (JobLauncher) ctx.getBean("jobLauncher"); или сделать Autowired для этого bean-компонента JobLauncher в главном классе и запускать определенные задания последовательно в определенном последовательном порядке, вызывая jobLauncher.run(job, jobParameters),

Вы можете получить конкретные job экземпляры из контекста, инициализированные на шаге № 2.

Вы всегда можете использовать любую упорядоченную коллекцию для размещения своих заданий и запуска заданий, просматривая эту коллекцию.

4. Этот метод работает до тех пор, пока ваш JobLauncher настроен на синхронность, т.е. основной поток ожидает jobLauncher.run() вызов завершить, и это поведение по умолчанию для jobLauncher.

Если вы определили свой jobLauncher для использования AsyncTaskExecutor, тогда задания будут запускаться параллельно, и последовательное упорядочение не будет поддерживаться.

Надеюсь, поможет!!

РЕДАКТИРОВАТЬ:

Я экспериментировал с @Order аннотация, как указал Стефан Николл, и кажется, что она помогает только в создании упорядоченной коллекции заданий и что вы можете выполнять итерации и запускать задания в указанном порядке.

Этот ниже компонент дает мне работу в указанном порядке,

@Component
public class MyJobs {
    @Autowired
    private List<Job> jobs;

    public List<Job> getJobs() {
        return jobs;
    }
}

и я могу сделать, MyJobs myJobs = (MyJobs) ctx.getBean("myJobs"); в основном классе определяется боб,

@Bean
    public MyJobs myJobs() {
        return new MyJobs();
    }

Я могу перебрать myJobs и запускайте задания в том порядке, который указан аннотацией @Order.

Order them.

@Bean
@Order(42)
public Job requestTickets() {
    return jobBuilderFactory.get(Config.JOB_REQUEST_TICKETS)
            .start(stepRequestTickets())
            .build();
}

See the javadoc of@Order Больше подробностей.

Вот иллюстрация решения.

Это так странно, похоже, что мы взломали процесс.

spring.batch.job.enabled = ложь

@SpringBootApplication
@EnableBatchProcessing
public class MyApplication {

    public static void main(String[] args)
            throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {

        ConfigurableApplicationContext ctx = SpringApplication.run(MyApplication.class, args);
        JobLauncher jobLauncher = (JobLauncher) ctx.getBean("jobLauncher");
        Job job1= (Job) ctx.getBean("job1");
        Job job2= (Job) ctx.getBean("job2");
        jobLauncher.run(job1,new JobParameters());
        jobLauncher.run(job2,new JobParameters());
    }

}

У меня недостаточно представителей, чтобы комментировать. Но пытались ли вы просто запустить свои работы в нужном вам порядке?

Вам нужно установить spring.batch.job.enabled=false в ваш application.properties, чтобы ваши задания не запускались автоматически.

Тогда просто используйте панель запуска, чтобы запускать ваши задания в нужном вам порядке.

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { TestConfiguration.class, TestDataSourceConfiguration.class, TestBatchConfig.class })
public class JobOrderTest {

    @Autowired
    JobLauncher jobLauncher;

    @Mock
    Job firstJob;

    @Mock
    Job secondJob;

    @Mock
    Job thirdJob;

    @Mock
    JobParametersValidator jobParametersValidator;

    @Test
    public void jobInOrderTest() throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {

        when(firstJob.getName()).thenReturn(UUID.randomUUID().toString());
        when(secondJob.getName()).thenReturn(UUID.randomUUID().toString());
        when(thirdJob.getName()).thenReturn(UUID.randomUUID().toString());
        when(firstJob.getJobParametersValidator()).thenReturn(jobParametersValidator);
        when(secondJob.getJobParametersValidator()).thenReturn(jobParametersValidator);
        when(thirdJob.getJobParametersValidator()).thenReturn(jobParametersValidator);

        jobLauncher.run(firstJob, new JobParameters());
        jobLauncher.run(secondJob, new JobParameters());
        jobLauncher.run(thirdJob, new JobParameters());
    }

}

Вот вывод

2016-12-30 09:48:36.457  INFO 144860 --- [cTaskExecutor-1] o.s.b.c.l.support.SimpleJobLauncher      : Job: [firstJob] launched with the following parameters: ...
2016-12-30 09:48:36.457  INFO 144860 --- [cTaskExecutor-1] o.s.b.c.l.support.SimpleJobLauncher      : Job: [firstJob] completed with the following parameters: ...
2016-12-30 09:48:36.478  INFO 144860 --- [cTaskExecutor-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [secondJob] launched with the following parameters: ...
2016-12-30 09:48:36.478  INFO 144860 --- [cTaskExecutor-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [secondJob] completed with the following parameters: ...
2016-12-30 09:48:36.508  INFO 144860 --- [cTaskExecutor-3] o.s.b.c.l.support.SimpleJobLauncher      : Job: [thirdJob] launched with the following parameters: ...
2016-12-30 09:48:36.508  INFO 144860 --- [cTaskExecutor-3] o.s.b.c.l.support.SimpleJobLauncher      : Job: [thirdJob] completed with the following parameters: ...

Если ваша одна работа зависит от второй и так далее, то сделайте что-то подобное.

@Configuration
@EnableBatchProcessing
@Import(DataSourceConfiguration.class)
public class AppConfig {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    public Job job(@Qualifier("step1") Step step1, @Qualifier("step2") Step step2) {
        return jobs.get("myJob").start(step1).next(step2).build();
    }

    @Bean
    protected Step step1(ItemReader<Person> reader, ItemProcessor<Person, Person> processor, ItemWriter<Person> writer) {
        return steps.get("step1")
            .<Person, Person> chunk(10)
            .reader(reader)
            .processor(processor)
            .writer(writer)
            .build();
    }

    @Bean
    protected Step step2(Tasklet tasklet) {
        return steps.get("step2")
            .tasklet(tasklet)
            .build();
    }
}
Другие вопросы по тегам