简体   繁体   中英

Sent Response after Spring Batch completed Job in Spring Boot

I have to upload CSV, convert it to Java Object and then persist in Database. I am using Spring Boot with Spring Batch to achieve this. I have gone through multiple tutorials. After analyzing those it seems Spring Batch Job run asynchronously as response sent to client before job completion. But I need to send response to client after job execution completed. Is it possible to do? Please help to resolve this issue. Thanks My Controller Code follows:

@RestController
public class AppRestCtrl {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    JobLauncher jobLauncher;

    @Autowired
    Job job;

    @PostMapping("/processFile")
    public ResponseEntity convertCsvToObject(@RequestParam("fileData") MultipartFile file) throws Exception {

        final Path rootLocation = Paths.get("uploads");

        if(!Files.exists(rootLocation)) {
            Files.createDirectories(rootLocation);
        }

        if(file.isEmpty()) {
            return ResponseEntity.badRequest().body("Empty File Not Allowed");
        }

        if(!file.getOriginalFilename().contains(".csv")) {
            return ResponseEntity.badRequest().body("File is Invalid!");
        }

        Files.deleteIfExists(rootLocation.resolve(file.getOriginalFilename()));
        Files.copy(file.getInputStream(), rootLocation.resolve(file.getOriginalFilename()));

        try {
            JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis())
                    .toJobParameters();
            jobLauncher.run(job, jobParameters);
        } catch (Exception e) {
            logger.info(e.getMessage());

        return ResponseEntity.ok("Batch Process Started Successfully!");
    }

}

Batch Config File:

@Configuration
public class BatchConfig {

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job job() {
        return jobBuilderFactory.get("job").incrementer(new RunIdIncrementer()).listener(new Listener())
                .flow(step1()).end().build();
    }

    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1").<ObjectNode, JsonNode>chunk(1)
                .reader(Reader.reader("uploads\\students.csv"))
                .processor(new Processor()).writer(new Writer()).build();
    }

}

it seems Spring Batch Job run asynchronously as response sent to client before job completion

This is true if the job launcher is configured with an asynchronous task executor. If the job launcher uses a synchronous task executor (which is the default), the job will be executed until completion. But in this case, the web client will be waiting until the job is completed which is probably what you don't want to happen (more details here: https://docs.spring.io/spring-batch/4.0.x/reference/html/job.html#runningJobsFromWebContainer ).

I need to send response to client after job execution completed

If your job execution time is fast enough to be acceptable as an execution time for a web request, then you can use the (default) synchronous task executor. In this case, you can send the response after job is completed. But as said, this is not recommended for long running jobs as the http request may timeout before the job is finished.

Trying to use a org.springframework.web.context.request.async.DeferredResult (or a similar approach) would be an ugly hack as it does not solve the problem. So I don't see a viable option for your use case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM