#java #spring-boot #asynchronous #completable-future #deferred-result
Вопрос:
Я понимаю некоторые идеи асинхронных сервисов, но не так много их закодировал, поэтому механика, особенно в Java, для меня нова. В принципе, у меня есть давно работающая служба, которую я хочу передать другому потоку и иметь возможность проверить ее состояние с помощью другой службы. На данный момент я могу приступить к работе, у меня пока нет возможности проверить это. Но хуже:
В почтовой службе asyncUploadSoftLayerFile
ниже:
@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;
}
}
Весна действительно делает то, что откладывается, и я вижу, что она породила работу в другом потоке. Но он не вернулся обратно к звонящему. Вместо этого я увидел:
2021-07-27 05:20:00 DEBUG o.s.web.servlet.DispatcherServlet - Exiting but response remains open for further handling
Так что это лишь частично дало мне то, что я хотел. Как я могу заставить Spring перенести работу в другой поток (и в идеале иметь возможность ссылаться на этот процесс с помощью другого вызова веб-службы), но сразу же возвращать какой-либо ответ веб-браузеру?
Это часть усилий, направленных на то, чтобы начать работу, но отслеживать процент завершения по мере ее выполнения.
Комментарии:
1. Название
DeferredResult
делает именно то, что оно делает. Это откладывает результат до тех пор, пока не будет что написать. Что несколько отличается от вашего варианта использования (по крайней мере, из вашего описания). Если вы этого хотите, запустите задание в фоновом режиме, верните какой-либо уникальный идентификатор для этого задания/процесса, создайте другую конечную точку для запроса статуса этого процесса. ЭтоDeferredResult
не то, что вам нужно для вашего случая использования. Также не используйтеForkJoinPool
для этого используйте однуAsyncTaskExecutor
из реализаций Spring для этого.2. @M. Deinum Спасибо вам за ваш ответ. Я смотрю на AsyncTaskExecutor, но хочу знать, почему я должен использовать его вместо ForkJoinPool. Делает ли Spring дополнительное отслеживание того, что он хочет управлять этими вложенными потоками? Бонусные баллы за указание того, где я могу хранить информацию о потоке, когда другой вызывающий абонент хочет сослаться на то, что было создано этим предыдущим запросом.
3. Он
ForkJoinPool
не предназначен для подобных вещей и может влиять на такие вещи, как параллельный поток или потоковая обработка. Речь идет просто об использовании правильного инструмента для работы. Вы не должны хранить информацию о потоке, вы должны хранить информацию о задании и периодически обновлять ее, чтобы вы также могли периодически ее читать.4. @M. Deinum Спасибо вам. Можете ли вы порекомендовать что-нибудь почитать о том, где хранить информацию о работе? Я обеспокоен тем, что он может работать на сервере с балансировкой нагрузки на OpenShift
5. Хранилище данных, которое вы используете, хорошо подходит.