简体   繁体   English

将CompletableFuture与@Async一起使用将为Spring Boot API返回空响应

[英]Using CompletableFuture with @Async returns an empty response for spring boot API

Here is my controller. 这是我的控制器。 I used postman to test if it's working but I am getting an empty response. 我使用邮递员来测试它是否正常工作,但是我收到了一个空的答复。 I used @EnableAsync in application configuration and @Async on the service. 我用@EnableAsync在应用程序配置和@Async的服务。 If I remove @Async on service layer it works but it doesn't run asynchronously. 如果我在服务层上删除@Async ,它可以工作,但不会异步运行。

@ApiOperation(value = "search person by passing search criteria event/title/role/host/is_current", response = ElasticSearchResultData.class)
@RequestMapping(value = "/async2/searchPerson", produces = "application/json", method = RequestMethod.POST)
public @ResponseBody CompletableFuture<ElasticSearchResultData> searchPersonAsync2(@RequestBody SearchCriteriaTo criteriaForDivNetFolderTo,
        HttpServletRequest request, HttpServletResponse response){
    LOGGER.info("searchPerson controller start");
    SearchCriteria searchCriteria = criteriaForDivNetFolderTo.getSearchCriteria();
    if (Util.isNull(searchCriteria)) 
        throw new IllegalArgumentException("search criteria should not be null.");

    try {
        CompletableFuture<ElasticSearchResultData> searchPerson = cubService.searchPersonAsync2(criteriaForDivNetFolderTo);
        ObjectMapper mapper = new ObjectMapper();
        LOGGER.info("search Person "+mapper.writeValueAsString(searchPerson));
        return searchPerson;
    } catch (Exception e) {
        LOGGER.error("Exception in searchPersonAsync controller "+e.getMessage());
    }
    return null;
}

Service 服务

@Async
@Override
public CompletableFuture<ElasticSearchResultData> searchPersonAsync2(SearchCriteriaTo searchCriteriaForDivNetFolderTo) {
   Long start = System.currentTimeMillis();
   LOGGER.info(":in searchPerson");
   CompletableFuture<ElasticSearchResultData> completableFuture = new CompletableFuture<>();
   ElasticSearchResultData searchResultData = null;
   SearchCriteria searchCriteria = searchCriteriaForDivNetFolderTo.getSearchCriteria();
   try {
        LOGGER.info("************ Started searchPerson by criteria ************");
        StringBuilder url = new StringBuilder();
        url.append(equilarSearchEngineApiUrl)
        .append(focusCompanySearchUrl)
        .append("/")
        .append("searchPerson")
        .append("?view=").append(VIEW_ALL)
        .append("&isProcessing=true");

        LOGGER.debug("Calling equilar search engine for focused company search, URL : " + url);
        LOGGER.info(searchCriteria.toString());
        String output = null;
        if (redisEnable != null && redisEnable) {
            output = cacheDao.getDataFromRestApi(url.toString(), RequestMethod.POST.name(), searchCriteria);
        } else {
            output = Util.getDataFromRestApi(url.toString(), RequestMethod.POST.name(), searchCriteria);
        }
        if (!Util.isEmptyString(output)) {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            searchResultData = objectMapper.readValue(output,
                            objectMapper.getTypeFactory().constructType(ElasticSearchResultData.class));
        }
        List<PersonSearchDetails> newPersonDetails = new ArrayList<PersonSearchDetails>();
        if (!Util.isNull(searchResultData) && !Util.isNullOrEmptyCollection(searchResultData.getPersonDetails())
                && !Util.isNullOrEmptyCollection(searchCriteriaForDivNetFolderTo.getNetworkFoldersData())) {
            for (PersonSearchDetails personDetail : searchResultData.getPersonDetails()) {
                String logoUrl = null;
                if(!Util.isNull(searchCriteria.getTargetFolderId())){
                    List<DiversityNetworkFolderTo> filteredFolderTos = searchCriteriaForDivNetFolderTo
                            .getNetworkFoldersData()
                            .stream()
                            .filter(folder -> folder.getId()
                            .longValue() == searchCriteria
                            .getTargetFolderId())
                            .collect(Collectors.toList());
                    logoUrl = getLogoUrl(personDetail.getPersonId(),
                            filteredFolderTos);
                } else {
                    logoUrl = getLogoUrl(personDetail.getPersonId(),
                            searchCriteriaForDivNetFolderTo.getNetworkFoldersData());
                }
                personDetail.setLogoUrl(logoUrl);
                newPersonDetails.add(personDetail);
            }
            searchResultData.setPersonDetails(newPersonDetails);
        }
        completableFuture.complete(searchResultData);
        return completableFuture;
    } catch (Exception e) {
        completableFuture.completeExceptionally(e);
        LOGGER.error(
                " ************** Error in proccessing searchPerson by criteria ************** " + e.getMessage());
    }
    Long end = System.currentTimeMillis();
    LOGGER.info(TIME_DURATION+(end - start)+"ms");
    return null;
}

It would be good to read more about async processing. 最好阅读有关异步处理的更多信息。 javadocs are usually a great start! 通常, javadocs是一个不错的开始!

If you really want to get the result from a Future method, you need to wait for it. 如果您真的想从Future方法获得结果,则需要等待。

There is a method public T get() method in the CompletableFuture API to wait for wait for the result to be created and return the result once it's done. CompletableFuture API中有一个方法public T get()方法来等待创建结果,并在完成后返回结果。

If your job is to search a database for the result and then return it - you will still have to wait for it async is not much help in here. 如果您的工作是在数据库中搜索结果,然后返回它-您仍然必须等待它异步在这里并没有太大帮助。 It would help you if you had to make multiple things at the same time, eg a call to DB, a web service and something else at the same time, then you can create an array of futures and wait for all of them to complete. 如果您必须同时进行多项操作(例如,对数据库的调用,Web服务和其他操作),这将对您有所帮助,那么您可以创建一系列期货并等待所有这些完成。

Or, let's say you're creating a POST method, so you can quickly validate the input and send to store to DB async while quickly returning the response to UI and hoping that your async method will be completed in another thread and not returning any errors to UI. 或者,假设您正在创建POST方法,因此您可以快速验证输入并发送到数据库异步存储,同时快速将响应返回给UI,并希望您的异步方法将在另一个线程中完成并且不会返回任何错误到UI。

This is a great technique when you know what you're doing, but think if & when you really need it before using it. 当您知道自己在做什么时,但在使用前先考虑是否真正需要它时,这是一种很棒的技术。

The short way to "fix" this is: “修复”此问题的简短方法是:

CompletableFuture<ElasticSearchResultData> searchPerson = cubService.searchPersonAsync2(criteriaForDivNetFolderTo);
ElasticSearchResultData result = searchPerson.get();
ObjectMapper mapper = new ObjectMapper();
LOGGER.info("search Person "+mapper.writeValueAsString(result));
return result;

( and obviously change the method return signature ) (并且显然更改方法的返回签名)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 CompletableFuture 将此代码转换为 Java 8 中的异步代码? 我正在使用 Spring 引导 - How to convert this code to async in Java 8 using CompletableFuture ? I am using Spring Boot 使用春天起动的空的肥皂邮差反应 - Empty soap postman response using spring boot 在 Spring Boot 的 @Async 注释中使用 CompletableFuture.supplyAsync 和 CompletableFuture.completedFuture - use of CompletableFuture.supplyAsync and CompletableFuture.completedFuture within @Async annotation in spring boot Spring 引导 Rest API 返回空 Z0ECD11C1D7A287401D148A2kBBD7A2 已使用 - Spring Boot Rest API Returns Empty JSON Used with Lombok Spring 引导 API 响应返回重复嵌套 JSON - Spring Boot API response returns repeating nested JSON 如何在Spring Boot中使用CompletableFuture并行调用方法多次 - How to call a method multiple times in parallel using CompletableFuture in Spring Boot Spring @ResponseStatus返回空响应 - Spring @ResponseStatus returns empty response 在 controller 中使用 @Async 和 CompletableFuture 可以提高我们 api 的性能吗? - is using @Async and CompletableFuture in controller can increase performance of our api? Spring Boot 2异步进行调用但不返回响应 - Spring Boot 2 Async making the call but not returning a response Springboot API返回空响应 - Springboot API returns empty response
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM