2017-07-06 2 views
1

Voici mon contrôleur. J'ai utilisé un facteur pour tester si ça fonctionne mais je reçois une réponse vide. J'ai utilisé @EnableAsync dans la configuration de l'application et @Async sur le service. Si je supprime @Async sur la couche de service, cela fonctionne mais il ne s'exécute pas de manière asynchrone.L'utilisation de CompletableFuture avec @Async renvoie une réponse vide pour l'API de démarrage par ressort

@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; 
} 
+0

je ne vois pas où cela * * async exigence vient. Ici, vous faites ce que vous devez faire, obtenez la requête, récupérez les données de la BD, et une fois que vous l'avez, répondez immédiatement. Il n'y a rien à faire de manière asynchrone. Cependant, pour moi, il semble que votre client demande de faire un appel * async * à partir de l'interface utilisateur, qui est peut-être ** AJAX ** ou similaire, ce qui n'a rien à voir avec ce code. Je recommande de supprimer toute cette logique * Future *. – Zilvinas

+0

L'ingénieur d'automatisation teste l'API avec 100 utilisateurs courants ce qui dégrade les performances de l'API. J'ai utilisé DefferredResult <> avec @async auparavant.Il a amélioré les performances de 50%. Donc j'ai voulu essayer CompletableFuture <>. – vk1

+0

Je me demande quelle performance il a amélioré si vous n'attendez pas et n'obtenez pas le résultat – Zilvinas

Répondre

0

Il serait bon de lire plus sur async traitement. javadocs sont généralement un bon début!

Si vous voulez vraiment obtenir le résultat d'une méthode Future, vous devez l'attendre.

Il existe une méthode public T get() dans l'API CompletableFuture pour attendre que le résultat soit créé et renvoyer le résultat une fois que c'est fait.

Si votre travail consiste à rechercher une base de données pour le résultat, puis le renvoyer - vous devrez toujours attendre async n'est pas beaucoup d'aide ici. Cela vous aiderait si vous deviez faire plusieurs choses en même temps, par ex. un appel à DB, un service Web et autre chose en même temps, alors vous pouvez créer un tableau de contrats à terme et attendre que tous les complètent.

Ou, disons que vous créez une méthode POST, afin que vous puissiez valider rapidement l'entrée et l'envoyer à stocker à DB async en revenant rapidement la réponse à l'interface utilisateur et espérant que votre méthode async sera terminée dans un autre thread et ne renvoyant aucune erreur à l'interface utilisateur.

Ceci est une excellente technique lorsque vous savez ce que vous faites, mais pensez si & lorsque vous en avez vraiment besoin avant de l'utiliser.

La courte façon de « réparer » c'est:

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

(et évidemment changer la signature de retour de la méthode)

+0

J'ai utilisé DefferedResult <> comme type de retour et @async utilisé aussi dans le service dans une autre implémentation d'api, il J'ai bien travaillé. Je me demande pourquoi je n'ai pas attendu les résultats et j'ai reçu la réponse. – vk1

+0

ElasticSearchResultData utilisé result = searchPerson.get() Toujours une réponse vide – vk1