Option 1: More than one RestTemplate
If you are changing the properties of the connections created, you will need to have one RestTemplate
per configuration. I had this very same problem recently and had two versions of RestTemplate
, one for "short timeout" and one for "long timeout". Within each group (short/long) I was able to share that RestTemplate
.
Having your calls change the timeout settings, create a connection, and hope for the best is a race condition waiting to happen. I would play this safe and create more than one RestTemplate
.
Example:
@Configuration
public class RestTemplateConfigs {
@Bean("shortTimeoutRestTemplate")
public RestTemplate shortTimeoutRestTemplate() {
// Create template with short timeout, see docs.
}
@Bean("longTimeoutRestTemplate")
public RestTemplate longTimeoutRestTemplate() {
// Create template with short timeout, see docs.
}
}
And then you can wire them in to your services as needed:
@Service
public class MyService {
private final RestTemplate shortTimeout;
private final RestTemplate longTimeout;
@Autowired
public MyService(@Qualifier("shortTimeoutRestTemplate") RestTemplate shortTimeout,
@Qualifier("longTimeoutRestTemplate") RestTemplate longTimeout) {
this.shortTimeout = shortTimeout;
this.longTimeout = longTimeout;
}
// Your business methods here...
}
Option 2: Wrap calls in a Circuit Breaker
If you are calling out to external services, you probably should be using a circuit breaker for this. Spring Boot works well with Hystrix, a popular implementation of the circuit breaker pattern. Using hystrix you can control the fallback for each service you call out to, and the timeouts.
Suppose you have two options for Service A: 1) Cheap but sometimes slow 2) Expensive but fast. You can use Hystrix to give up on Cheap/Slow and use Expensive/Fast when you really need to. Or you can have no backup and just have Hystrix call a method that provides a sensible default.
Untested example:
@EnableCircuitBreaker
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp .class, args);
}
}
@Service
public class MyService {
private final RestTemplate restTemplate;
public BookService(RestTemplate rest) {
this.restTemplate = rest;
}
@HystrixCommand(
fallbackMethod = "fooMethodFallback",
commandProperties = {
@HystrixProperty(
name = "execution.isolation.thread.timeoutInMilliseconds",
value="5000"
)
}
)
public String fooMethod() {
// Your logic here.
restTemplate.exchange(...);
}
public String fooMethodFallback(Throwable t) {
log.error("Fallback happened", t);
return "Sensible Default Here!"
}
}
The fallback method has options too. You could annotate that method with @HystrixCommand
and attempt another service call. Or, you could just provide a sensible default.