0
votes

I am new to multi-threading in Java and trying to make a Spring project with Callable interface and Future Class.

I am fetching all the records in dynamo db and for each record I am makin a multi-threaded call to an external service.

But I am getting this error:

nested exception is java.util.concurrent.ExecutionException: org.springframework.web.client.HttpServerErrorException: 500 null] with root cause

My Code :

Controller:

@Autowired
public RestTemplate restTemplate;

@Autowired
public MyCallable myCallable;
@GetMapping("/myApp-multithread")
public String getQuoteOnSepThread() throws InterruptedException, ExecutionException {
    System.out.println("#################################################Multi Threaded Post Call######################");
    ExecutorService executor= Executors.newFixedThreadPool(10);
    List<Future<String>> myFutureList= new ArrayList<Future<String>>();
    long startTime=System.currentTimeMillis()/1000;

    Iterable<Customer> customerIterable=repo.findAll();
    List<Customer> customers=new ArrayList<Customer>();
    customerIterable.forEach(customers::add);


    for(Customer c:customers) {

        myCallable.sendCustomerToInterface(c);
        //System.out.println(c);
        Future<String> future= executor.submit(myCallable);
        myFutureList.add(future);

    }

    for(Future<String> fut:myFutureList) {
        fut.get();
    }
    executor.shutdown();

    long timeElapsed= (System.currentTimeMillis()/1000)-startTime;

    System.out.println("->>>>>>>>>>>>>>>Time Elapsed In Multi Threaded Post Call<<<<<<<<<<<<<<<-"+timeElapsed);
    return "Success";

}

MyCallable Class:

public class MyCallable implements Callable<String>{

@Autowired
public RestTemplate restTemplate;

//int index=-1;

Customer c= c= new Customer();;
public void sendCustomerToInterface(Customer cust) {

    c= cust;
}

@Override
public String call() throws Exception {

    System.out.println("Customer no"+ c.getId() +"On thread Number"+Thread.currentThread().getId());
    return restTemplate.postForObject("http://localhost:3000/save", c, String.class);

}

}

Can someone help me with this

Edit:

Full Stack Trace with of the error:

org.springframework.web.client.HttpServerErrorException: 500 null at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:88) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:707) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:660) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:620) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:387) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at com.OCADemoClient.OCADemoClient.MyCallable.call(MyCallable.java:32) ~[classes/:na] at com.OCADemoClient.OCADemoClient.MyCallable.call(MyCallable.java:1) ~[classes/:na] at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_181] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_181] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_181] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]

1
can you share the full stacktrace when doing a POST call - Pant
I have added the full stack trace of the error - Kshitiz Sharma
It simply show that org.springframework.web.client.HttpServerErrorException: 500 means there is problem with communication. can you please try your restTemplate.postForObject("localhost:3000/save", c, String.class); with any rest client and check its working or not. - user4477122
@Pant Stil same error after making the suggested changes. But this time , stack trace was printed for each element which faced the error. and still only the last element is being printed again and again - Kshitiz Sharma
@ArunKumar I tried that Arun and it is working fine with Potman - Kshitiz Sharma

1 Answers

1
votes

According to the JavaDoc:

Exception thrown when attempting to retrieve the result of a task that aborted by throwing an exception.

The problem seems to be that for some Customer the call

    restTemplate.postForObject("http://localhost:3000/save", c, String.class);

results in a server error with an HTTP response code "500"


I only noticed after reading your comment:

You have only one MyCallable that is shared over all Customers.

This won't work, because your MyCallable is a stateful object (it stores the Customer with void sendCustomerToInterface(Customer cust) and needs to retrieve this specific Customer later in the call() method).

To make it work you could rewrite MyCallable like this:

public class MyCallable implements Callable<String>{

    private RestTemplate restTemplate;
    private Customer c;

    public MyCallable(RestTemplate rt, Customer cust) {
        this.restTemplate = rt;
        this.c = cust;
    }

    @Override
    public String call() throws Exception {
        System.out.println("Customer no"+ c.getId() +"On thread Number"+Thread.currentThread().getId());
        return restTemplate.postForObject("http://localhost:3000/save", c, String.class);

    }
}

and in the controller you would write

for(Customer c:customers) {

    MyCallable myCallable = new MyCallable(restTemplate, c);
    //System.out.println(c);
    Future<String> future= executor.submit(myCallable);
    myFutureList.add(future);

}

BTW your code is inefficient. You could skip generating the customers list and just write

for (Customer c: repo.findAll()) {
    //...
}