0

I am facing issue with restTemplate, in a multithreaded environment. I am calling a Rest api with url http://localhost:8080/search, its a post request and I pass a object which have search parameters. I use this to search user,dept etc. This returns a response search object which has such structure, First one is for user and second is for dept

{"totalCount":2,"startIndex":0,"endIndex":1,"resultList":[{"username":"a", userid:"1}, {"username":"b", userid:"2"}, {"username":"c", userid:"3"} ]}
{"totalCount":2,"startIndex":0,"endIndex":1,"resultList":[{"deptname":"a", deptid:"1"}, {"deptid":"b", deptid:"2"} ]}

Sometimes if api is slow the response return is overridden, like for dept and user the same response will be returned like

{{"totalCount":2,"startIndex":0,"endIndex":1,"resultList":[{"username":"a", userid:"1}, {"username":"b", userid:"2"}, {"username":"c", userid:"3"} ]}

I am autowiring a single instance of restTemplate. Also I have tried creating a new instance of restTemplate for each request but that didnt helped.

I am autowiring a single instance of restTemplate. Also I have tried creating a new instance of restTemplate for each request but that didnt helped.

------------Update-------------

Controller Code is something like:

            @RequestMapping("search")
    public @ResponseBody Map<String, Object> search(String type,
        String start, Integer count) {

    Map<String, Object> responseJson = new HashMap<>();

    Criteria criteria = new Criteria();
    criteria.setCount(count);
    criteria.setStartCount(start);
    criteria.setType(type);

    Result<?> result;
    String url = "http://localhost:8080/search";
    HttpEntity<Object> httpEntity = new HttpEntity<>();
    ResponseEntity<? extends Object> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, Result.class);

    if (response.getStatusCode() == HttpStatus.OK) {
        responseJson = (Result<?>) response.getBody();
    }

    return responseJson;
}

I have also checked the API code and seen that they are sending correct response when I received the overridden response. So looks like the request parameters are passing correctly and the response what API is sending is correct.

user12026310
  • 11
  • 1
  • 4
  • 1
    Welcome to Stack Overflow! Please take the tour and read through [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) and post a [Minimal, Complete, and Verifiable](https://stackoverflow.com/help/mcve) example of your attempt and say specifically where you're stuck. – brass monkey Sep 05 '19 at 16:20
  • 1
    Welcome to Stack Overflow! Sounds like you have problem with your controller using shared variable. Please post your controller code so that we can help you. – Pasupathi Rajamanickam Sep 05 '19 at 16:42
  • Added controller code in my question. – user12026310 Sep 05 '19 at 16:50
  • Are you using global variables instead of local variables in you Controller? If so, that's causing it. Show us the whole code of your controller class (omit non relevant code). – Matheus Sep 05 '19 at 19:26
  • I dont think I am using any global variables, the parameter that I am getting in the request are then send to API. Updated code. – user12026310 Sep 06 '19 at 03:12
  • At this point, I am thinking the problem is in the server side. – Edward Aung Sep 10 '19 at 06:15
  • Thanks Edward, I tried the same request from postman and everytime response is same. – user12026310 Sep 13 '19 at 10:43
  • I realized that there was a global variable in my Result object which was causing this. Thanks for help. – user12026310 Sep 16 '19 at 10:02

2 Answers2

0

If my memory serves me well, RestTemplate's exchange method is not thread-safe. That is why Spring does not create RestTemplate as a bean. (RestTemplate thread-safety question)

Autowire and use RestTemplateBuilder to get a new RestTemplate. It will solve your problem.

@Autowired RestTemplateBuilder restTemplateBuilder; 

@RequestMapping("search")
public @ResponseBody Map<String, Object> search(String type,
        String start, Integer count) {

    Map<String, Object> responseJson = new HashMap<>();

    Criteria criteria = new Criteria();
    criteria.setCount(count);
    criteria.setStartCount(start);
    criteria.setType(type);

    Result<?> result;
    String url = "http://localhost:8080/search";
    HttpEntity<Object> httpEntity = new HttpEntity<>();
    RestTemplate restTemplate = restTemplateBuilder.build(); // <-- here here
    ResponseEntity<? extends Object> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, Result.class);

    if (response.getStatusCode() == HttpStatus.OK) {
        responseJson = (Result<?>) response.getBody();
    }

    return responseJson;
}
Edward Aung
  • 3,014
  • 1
  • 12
  • 15
  • Thanks for reply Edward, RestTemplateBuilder is part of spring boot and I am not using it. – user12026310 Sep 06 '19 at 09:18
  • If that's the case, given the RestTemplate's exchange method is not thread-safe, why don't you use a factory as a bean (autowire this factory) and generate the RestTemplate for you to use ? – Edward Aung Sep 08 '19 at 23:55
  • I tried creating a new instance of RestTemplate for each request but it still does not work. – user12026310 Sep 10 '19 at 06:10
0

RestTemplate is not a thread-safe class so the use of it in a multithreaded environment would get into a weird situation. For avoiding that, you create an instance on each request by simply using the new operator

RestTemplate restTemplate = new RestTemplate();

Vishal Pawar
  • 750
  • 7
  • 11