Shilpi
Shilpi

Reputation: 119

@Retryable is not working when calling from a method

Below is my application class. The flow is like the DEToken class from here and from DEToken I call RestConnection where I have the @retryable method.

@SpringBootApplication
@EnableRetry
public class SpringBootTrfficApplication implements CommandLineRunner {

    Enter code here

    @Autowired
    DEToken deToken;

    @Autowired
    SyncService syncService;
    public static void main(String[] args) {
        SpringApplication.run(SpringBootTrfficApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        deToken.getToken();
    }
}

DEToken class: from getToken I am calling RestConnect where I have the @Retrable method:

@Service
public class DEToken {
    private Logger logger = LogManager.getLogger(getClass());

    @Autowired
    RestConnection restConnection;

    @Autowired
    private Environment env;

    public String accessToken;

    public void getToken() {
        System.out.println("hello from get token");
        //String getJsonPayload = "{\"Query\":{\"RegisterExtensionWithDE\":{\"pid\": \"\",\"providerInsName\":" +
        //env.getProperty("provider.ins") + "}}}";
        //String str = restConnection.restPost(
        //    env.getProperty("rest.de.url"), getJsonPayload);

        try {
            String getJsonPayload =
                "{\"Query\":{\"RegisterExtensionWithDE\":{\"pid\": \"\",\"providerInsName\":" +
                env.getProperty("provider.ins") + "}}}";
            StringBuffer tokenResult =
                restConnection.restPost(env.getProperty("rest.de.url"),
                                        getJsonPayload);
            System.out.println(tokenResult);
            JSONObject xmlJSONObj = XML.toJSONObject(tokenResult.toString());
            JSONObject registration = new JSONObject();
            if (xmlJSONObj.has("Registration")) {
                registration  = xmlJSONObj.getJSONObject("Registration");
                if (registration.has("accessToken")) {
                    accessToken = registration.get("accessToken").toString();
                }
                else
                    logger.info("no accessToken from DE");
            }
            else
                logger.info("no Registration object from DE");
        }
        catch (Exception e) {
            logger.error("Exception while fetching accesstoken from DE ");
            logger.error(e.getMessage());
        }
    }
}

My REST connection class where I have retryable method:

@Service
public class RestConnection {

    private Logger logger = LogManager.getLogger(getClass());

    @Autowired
    private Environment env;

    public void setBaseUrl(String value, String ip) {
        //baseUrl = value;
        HttpsURLConnection.setDefaultHostnameVerifier(
            (hostname, session) -> hostname.equals(ip));
    }


    /*
     * REST post call
     */
    @Retryable(value = {IOException.class, ConnectException.class},
               maxAttempts = 4,
               backoff = @Backoff(5000))
    public StringBuffer restPost(String restUrl, String payload) {
        StringBuffer sb = new StringBuffer();
        HttpURLConnection conn = null;
        try {
            URL url = new URL(restUrl);
            String protocol = url.getProtocol();
            if (protocol.toLowerCase().equals("http")) {
                conn = (HttpURLConnection)url.openConnection();
            }
            else if (protocol.toLowerCase().equals("https")) {
                //setTrustedCert();
                conn = (HttpsURLConnection)url.openConnection();
            }
            else {
                logger.info("Protocol is neither HTTP nor HTTPS");
            }
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("version", env.getProperty("de.version"));
            conn.setRequestProperty("accessToken", env.getProperty("access.token"));
            conn.setRequestProperty("requestHost", env.getProperty("server.de.host"));
            conn.setRequestProperty("requestPort", env.getProperty("server.port"));
            conn.setRequestProperty("requestProtocol",
                                    env.getProperty("server.de.protocol"));
            PrintWriter pout =
                new PrintWriter(
                    new OutputStreamWriter(
                        conn.getOutputStream(), "UTF-8"),
                    true);
            pout.print(payload);
            pout.flush();
            pout.close();

            InputStream isi = conn.getInputStream();
            InputStreamReader isr = new InputStreamReader(isi);
            int numCharsRead1;
            char[] charArray1 = new char[1024];

            while ((numCharsRead1 = isr.read(charArray1)) > 0) {
                sb.append(charArray1, 0, numCharsRead1);
            }
            isr.close();
            isi.close();
        }
        catch (MalformedURLException e) {
            logger.error("MalformedURLException in restAccessTokenPOST..." +
                         e.getMessage());
            //e.printStackTrace();
        }
        catch (IOException e) {
            logger.error("IOException in restAccessTokenPOST..." +
                         e.getMessage());
            e.printStackTrace();
        }
        catch (Exception e) {
            logger.error("Exception in restAccessTokenPOST..." +
                         e.getMessage());
            e.printStackTrace();
        }
        finally {
            if (null != conn)
                conn.disconnect();
        }
        return sb;
    }

    @Recover
    public String helpHere(ConnectException cause) {
        System.out.println("Recovery place! ConnectException");
        return "Hello";
    }

    @Recover
    public String helpHere(IOException cause) {
        System.out.println("Recovery place! ArithmeticException");
        return "Hello";
    }

    @Recover
    public String helpHere(Exception cause) {
        System.out.println("Recovery place! Exception");
        return "Hello";
    }

    @Recover
    public String helpHere() {
        System.out.println("Recovery place! Exception");
        return "Hello";
    }

    @Recover
    public String helpHere(Throwable cause) {
        System.out.println("Recovery place! Throwable");
        return "Hello";
    }
}

Upvotes: 3

Views: 2361

Answers (1)

Vikrant Kashyap
Vikrant Kashyap

Reputation: 6846

Considering you see your function restPost() implementation,

@Retryable(value = {IOException.class, ConnectException.class},
           maxAttempts = 4,
           backoff = @Backoff(5000))
public StringBuffer restPost(String restUrl, String payload) {
    try {
        // Your code
    }
    catch(IOException ex){ // These catch block handles the exception
                           // and nothing to throw to retryable.
    }
    catch(MalformedURLException ex){ // More catch blocks that you
                                     // define to handle exception.
    }
}

Here you handle all of the exceptions that can be a cause to revoke the retry and recover methods.

Note: Recoverable methods only execute when a exception is thrown, not handled by any try-catch block.

Whatever exception is raised by method restPost() is handled by the method try-catch block itself and there are no exceptions that had been rethrow by a catch block.

Now, Spring-Retry is unable to get any exception (because it is handled by the method try-catch block). So, no recovery method will be executed.

Solution: you should remove those catch blocks from the method definition on which you want to perform retry or recover.

Please do the needful and it will work like a charm... :)

Upvotes: 1

Related Questions