I have a Java code snippet that uses CompletableFuture to retrieve data asynchronously.
@GetMapping("/voyagePointData/{reportType}")
@PreAuthorize("@generalGuard.isResourceAllowed(authentication, #accountId) && hasAuthority('acl.map.device.READ')")
public ResponseEntity<List<ReportVoyagePointBean>> getVoyagePointData(@RequestParam(value = "accountId") int accountId,
@RequestParam(value = "ids") Set<Integer> ids,
@RequestParam("dateFrom") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime dateFrom,
@RequestParam("dateTo") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime dateTo,
@RequestParam(value = "onlySkipped") boolean onlySkipped,
@PathVariable(value = "reportType") String reportType,
@AuthenticationPrincipal UserBean userBean) throws NoDataException {
AccountEntity account = accountService.findById(accountId).orElseThrow(() -> new NoDataException("Account not exist"));
ZoneId userTimeZone = ZoneId.of(userBean.getUserTimeZone());
DateTimeFormatter zoneTimeFormatter = DateTimeFormatter.ofPattern(ModelsConstants.PATTERN_TIME_ONLY_MINUTES).withZone(userTimeZone);
CompletableFuture<List<ReportVoyagePointBean>> future = CompletableFuture.supplyAsync(() -> {
try {
return reportService.getVoyagePointData(
new ReportInfoBean(dateFrom, dateTo, account, userBean.getUserTimeZone(), zoneTimeFormatter), ids, reportType, onlySkipped);
} catch (NoDataException e) {
throw new RuntimeException(e);
}
}, executorService);
try {
List<ReportVoyagePointBean> result = future.get();
return new ResponseEntity<>(result, HttpStatus.OK);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
However, when I call future.get(), it gets stuck and doesn't return anything, leading to infinite waiting. If I call reportService.getVoyagePointData without CompletableFuture and with the same parameters, it works fine and returns all data.
Things I've tried that didn't help:
Thanks in advance for any help!
EDIT: Initializations of ExecutorService that I tried:
private final ExecutorService executorService = Executors.newCachedThreadPool();
private final ExecutorService executorService = Executors.newFixedThreadPool(6);
//and using this config
@Configuration
public class ExecutorConfig {
@Bean
public ExecutorService getExecutor() {
return new ThreadPoolExecutor(1, 5, 4, TimeUnit.MINUTES,
new ArrayBlockingQueue<>(50), Executors.defaultThreadFactory(), new RejectedExecutionHandlerImpl());
}
}
Solved!
The main reason for this error was my entites that were part of my code inside CompletableFuture and some part of these entities are lazy initialized and they needed to connect to db in order to fetch data. I solved this by creating a DTO and initialize it above CompletableFuture.