@Retryable
doesn't seem to be working on 2nd level of methods as in sphRemoteCall
below. I see that a proxy is created but it is never retried on failures.
Once I moved @Retryable
to the 1st level of methods like getSubscriberAccount
, it's started working.
Example below:
@Service
public class SphIptvClient extends WebServiceGatewaySupport {
//Works over here
@Retryable(maxAttempts=3, backoff=@Backoff(delay=100))
public GetSubscriberAccountResponse getSubscriberAccount(String loginTocken, String billingServId) {
GetSubscriberAccountResponse response = (GetSubscriberAccountResponse) sphRemoteCall(sphIptvEndPoint, getSubAcc, "xxxxx");
return response;
}
/*
* Retryable is not working on the 2nd level methods in the bean.
* It works only with methods which are called directly from outside
* if there is 2nd level method, like this, Retryable is not working.
*/
//@Retryable
private Object sphRemoteCall(String uri, Object requestPayload, String soapAction) {
log.debug("Calling the sph for uri:{} and soapAction:{}", uri, soapAction);
return getWebServiceTemplate().marshalSendAndReceive(uri, requestPayload, new SoapActionCallback(soapAction));
}
}
@Configuration
@EnableRetry
public class SphClientConfig {
@Bean
public SphIptvClient sphIptvClient() {
SphIptvClient client = new SphIptvClient();
return client;
}
}
First, you need to enable Spring Retry. You can achieve this by adding the @EnableRetry annotation to your @SpringBootApplication or @Configuration class. You can now use @Retryable to annotate any method to be a candidate or retry and @Recover to specify fallback methods.
Spring Retry provides an ability to automatically re-invoke a failed operation. This is helpful where the errors may be transient (like a momentary network glitch).
Spring Retry library (https://github.com/spring-projects/spring-retry) provides a declarative support to retry failed operations as well as fallback mechanism in case all the attempts fail.
public interface BackOffPolicy. Strategy interface to control back off between attempts in a single retry operation . Implementations are expected to be thread-safe and should be designed for concurrent access.
So this is a super late answer, but since I've just come here and confronted the same problem (again, after years ago wrestling with transactions) I'll furnish a little more fleshed out solution and hopefully someone will find it useful. Suffice to say that @M. Deinum's diagnosis is correct.
In the above case, and to paraphrase Understanding AOP proxies, any place where SphIptvClient
gets autowired will be given a reference to a proxy which Spring Retry will create when @EnableRetry
is handled:
"The
@EnableRetry
annotation creates proxies for@Retryable
beans" - Declarative Retry - Spring Retry
Once getSubscriberAccount
has been invoked and execution has passed through the proxy and into the @Service
instance of the object, no reference to the proxy is known. As a result sphRemoteCall
is called as if there were no @Retryable
at all.
You could work with the framework by shuffling code around in such a way as to allow getSubscriberAccount
to call a proxy-ed sphRemoteCall
, which requires a new interface and class implementation.
For example:
public interface SphWebService {
Object sphRemoteCall(String uri, Object requestPayload, String soapAction);
}
@Component
public class SphWebServiceImpl implements SphWebService {
@Retryable
public Object sphRemoteCall(String uri, Object requestPayload, String soapAction) {
log.debug("Calling the sph for uri:{} and soapAction:{}", uri, soapAction);
return getWebServiceTemplate().marshalSendAndReceive(uri, requestPayload, new SoapActionCallback(soapAction));
}
}
@Service
public class SphIptvClient extends WebServiceGatewaySupport {
@Autowired
SphWebService sphWebService;
@Retryable(maxAttempts=3, backoff=@Backoff(delay=100))
public GetSubscriberAccountResponse getSubscriberAccount(String loginTocken, String billingServId) {
GetSubscriberAccountResponse response = (GetSubscriberAccountResponse) this.sphWebService.sphRemoteCall(sphIptvEndPoint, getSubAcc, "xxxxx");
return response;
}
}
@Configuration
@EnableRetry
public class SphClientConfig {
// the @Bean method was unnecessary and may cause confusion.
// @Service was already instantiating SphIptvClient behind the scenes.
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With