0

I have two Java Spring Boot web service apps on the same server calling each other via REST. Service A calls Service B and the latter successfully acts upon the notfication. THE PROBLEM is that Service A never receives the acknowlegement from Service B, so it thinks it has failed, and in accordance with its looping recovery logic, it tries again…and again…and again. Service B ends up doing 3 times the work for no added benefit.

The relevant code (stripped down and falsified to protect the guilty) is as follows:

Service A:

public void giveOrderToServiceB(@RequestBody CustomClass message) {
...    
org.springframework.web.client.RestTemplate template = new RestTemplate(clientHttpRequestFactory());
com.mycompany.CustomReply reply = template.postForObject(serviceBUrl, message, CustomReply.class);

Service B REST Controller:

@PostMapping(value="ExecuteTheWork", produces=org.springframework.http.MediaType.APPLICATION_JSON_VALUE, consumes=MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody CustomReply executeTheWork(@RequestBody CustomClass thing) {
    // do something with the thing...
   CustomReply reply = new CustomReply();
    reply.setReply("Successfully executed the work.");
    return reply;
}

The actual exception caught by Service A after calling RestTemplate.postForObject() is

java.net.SocketTimeoutException: Read timed out

Please advise.

Howard007
  • 124
  • 7
  • Have you checked that Service B actually finishes it's method? I guess the culprit lies somewhere in `// do something with the thing...` – dunni Nov 21 '18 at 18:59
  • Thanks. Yes, it executes, parses an XML file, makes calls to a database (I can query to see the results) and the logging statement before the final return statement succeeds. – Howard007 Nov 21 '18 at 19:21
  • I'm wondering if there is something about the JSON marshalling and un-marshalling. Since these services are in separate JVMs they aren't actually referencing the same instances of the return object. – Howard007 Nov 21 '18 at 19:21
  • 1
    Try to add time to your reste template by doing like this : @Bean public RestTemplate restTemplate( RestTemplateBuilder restTemplateBuilder) { return restTemplateBuilder .setConnectTimeout(500) .setReadTimeout(500) .build(); } Else try to tell us what's is the url of every service ? – Abder KRIMA Nov 21 '18 at 19:38
  • Inexplicably, it seems to be working now; the return message is getting back to the caller. The only change I made related to this was to put the declaration of the return class variable towards the top of the method body. Go figure. – Howard007 Nov 21 '18 at 20:05
  • Sometimes it works; mostly it fails. – Howard007 Nov 21 '18 at 20:25

2 Answers2

0

OK, I think I got it. I don't send the response back from Service B until after the method has completed all of its work, which can take several seconds to several minutes. If I immediately answer (and skip the processing), it works consistently. Need to spin off the actual work to a separate thread. Cheeers

Howard007
  • 124
  • 7
0

When you are registering the bean of rest template in your application it must then configure it with a timeout. Following is the Spring application config file

package com.temp.project.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class TempProjectConfig {

    /**
     * Set Timeout for HTTP requests
     * @return
     */
    @Bean
    public ClientHttpRequestFactory getClientHttpRequestFactory() {
        int timeout = 1200000; // here is the timeout property set for rest template
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
                = new HttpComponentsClientHttpRequestFactory();
        clientHttpRequestFactory.setConnectTimeout(timeout);
        return clientHttpRequestFactory;
    }

    /**
     * RestTemplate to call REST endpoints
     * @param clientHttpRequestFactory
     * @return
     */
    @Bean
    public RestTemplate getRestTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
        return new RestTemplate(clientHttpRequestFactory);
    }

}
Asad Shakeel
  • 1,949
  • 1
  • 23
  • 29