spring retry

Jackie
2 min readJun 5, 2021

similar to circuit breaker, spring retry is a mechanism to handle for intermittent service unavailability and fallback if that has been sustained.

my code has been working well

@Recover public boolean altXX(String date){ ...... return false; } @Retryable(value = DataXXXException .class, maxAttempts = 10, backoff = @Backoff(delay = 30_000)) public boolean xxCheck(String date) throws DataXXXException { //biz logic here log.error("capturing the error", e); throw new DataXXXException ("XX Data not yet ready"); } return true; }

it would log the error several times before either it return a true when the data is available or return false after 10 tries.

till a state it starts to do xxCheck, then went straight to return false, without logging any error.

it has really confused me.

i then moved on to update the recover method to log the DataXXXException,

@Recover public boolean altXX(DataXXXExceptione, String date){ ... return false; }

which then instead of returning the false, it now stop the thread and straight away throw a NPE.

2021-06-05 14:15:21,946 [main] ERROR o.s.b.SpringApplication - Application run failed java.lang.NullPointerException: null ... at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.retry.interceptor.RetryOperationsInterceptor$1.doWithRetry(RetryOperationsInterceptor.java:93) at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:329) ... 35 common frames omitted Wrapped by: org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method; nested exception is java.lang.NullPointerException at org.springframework.retry.annotation.RecoverAnnotationRecoveryHandler.recover(RecoverAnnotationRecoveryHandler.java:70) at org.springframework.retry.interceptor.RetryOperationsInterceptor$ItemRecovererCallback.recover(RetryOperationsInterceptor.java:142) at org.springframework.retry.support.RetryTemplate.handleRetryExhausted(RetryTemplate.java:539) at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:387) at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:225) at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:116) at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:163) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ... org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method; nested exception is java.lang.NullPointerException .... Caused by: java.lang.NullPointerException: null

at the same time, there is another retryable, which starts throwing

Wrapped by: org.springframework.retry.backoff.BackOffInterruptedException: Thread interrupted while sleeping; nested exception is java.lang.InterruptedException: sleep interrupted

and

ERROR while querying for country ccy java.sql.SQLException: HikariDataSource HikariDataSource (null) has been closed.

after some investigation, turns out that’s due to a code in the //biz logic here block, which throws a RunTimeException (NPE), which was not captured and straightaway to recover.

and the thread calling is the `main` thread, which tries to stop the application.

as the retryable thread has received the signal to stop, same the hikariDatasource, which throws the interuppted exception

Originally published at https://lwpro2.dev on June 5, 2021.

--

--