0

I get some of the idea of async services, but haven't coded many, so the mechanics especially in Java are new to me. Basically, I have a long running service that I want to fork off to another thread and be able to check in on the status of it using a different service. For now, I can get the work started, I don't have a way to check in on it yet. But worse:

In the POST service asyncUploadSoftLayerFile below:

@RestController
@RequestMapping("/")
public class MyController {
   ...
    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping("/async-files")
    public DeferredResult<ResponseEntity<JobExecutionResult>>       asyncUploadSoftLayerFile(@RequestParam MultipartFile file) throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, IOException, JobExecutionAlreadyRunningException{
        logger.info("Received async-CompleteableFuture request");
        DeferredResult<ResponseEntity<JobExecutionResult>> output = new DeferredResult<ResponseEntity<JobExecutionResult>>();
        ForkJoinPool.commonPool().submit(() -> {
            logger.info("Processing in separate thread: Thread-ID="+Thread.currentThread().getId());

            JobExecutionResult jobExecutionResult = null;
            try {
                myReallyLongRunningProcess();
            } catch (JobParametersInvalidException | JobExecutionAlreadyRunningException | JobRestartException
                    | JobInstanceAlreadyCompleteException | IOException e) {
                logger.error("Error processing /async-files upload in Thread-ID: "+Thread.currentThread().getId(),e);
                throw new RuntimeException(e);
            }
            if (!"COMPLETED".equals(jobExecutionResult.getExitStatus())) {
                throw new UploadFileException(file.getOriginalFilename() + " exit status: " + jobExecutionResult.getExitStatus());
            }
            ResponseEntity<JobExecutionResult> responseEntity = ResponseEntity.ok(jobExecutionResult);
            output.setResult(responseEntity);
        });
        
        return output;
    }
}

Spring does do it's deferred thing, and I can see it spawned the work off to another thread. But it did not return back to the caller. Instead I saw:

2021-07-27 05:20:00 DEBUG o.s.web.servlet.DispatcherServlet - Exiting but response remains open for further handling

So it only partially gave me what I wanted. How can I get Spring to spawn the work off to another thread, (and ideally be able to refer to that process by another web service call), but immediately return some sort of response to the web browser?

This is part of an effort to start work but track the percentage complete as it goes along.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
Woodsman
  • 901
  • 21
  • 61
  • The name `DeferredResult` does exactly what it does. It defers the result until there is something to write. Which is something different than your usecase (at least from your description). If you want that, run the job in the background, return some unique id for that job/proces, create an other endpoint to query status of that process. The `DeferredResult` isn't what you want for your usecase. Also don't use the `ForkJoinPool` for that use one fo the Spring `AsyncTaskExecutor` implementations for that. – M. Deinum Jul 27 '21 at 09:30
  • @M.Deinum Thank you for your reply. I'm looking at the AsyncTaskExecutor but wish to know why I should use that instead of ForkJoinPool. Is Spring doing some extra tracking that it wishes to manage these sub threads? Bonus points for saying where I can store the thread info when another caller wants to reference what was created by this previous request. – Woodsman Jul 27 '21 at 14:25
  • The `ForkJoinPool` isn't meant for things like this and might influence things like parallel stream or stream processing. It is just about using the right tool for the job. You shouldn't store the thread info you should store the job info and periodically update that so you can also periodically read that. – M. Deinum Jul 27 '21 at 14:34
  • @M.Deinum Thank you. Can you recommend something to read on where to store the job info? I'm concerned that it might run on a load balanced server on OpenShift – Woodsman Jul 27 '21 at 14:53
  • The datastore you are using is a good fit. – M. Deinum Jul 27 '21 at 17:57

0 Answers0