简体   繁体   中英

@Recover methods are not triggered with @Retryable

I followed this question after getting ExhaustedRetryException on @Retryable function. The @Retryable function is retrying.

Here's the Delegate with the @Retryable function:

@Component
public class OrderRequestDelegate {

    private static final Logger LOGGER = LoggerFactory.getLogger(OrderRequestDelegate.class);

    private final OrderRequestDao orderRequestDao;
    private final SqsQueueDao sqsQueueDao;

    @Autowired
    public OrderRequestDelegate(OrderRequestDao orderRequestDao, SqsQueueDao sqsQueueDao) {
        this.orderRequestDao = orderRequestDao;
        this.sqsQueueDao = sqsQueueDao;
    }

    @Retryable(include=NoResultException.class, backoff = @Backoff(delay = 100, maxDelay = 101), maxAttempts = 5)
    public OrderRequest processItem(String storeId, String message) {
        Long id = 999L;
        OrderRequest result = orderRequestDao.findOne(id);
        if (result == null) {
            LOGGER.info("Tried in retryable");
            throw new NoResultException();
        }
        return result;
    }

    @Recover
    public void recover(NoResultException e, Long id) {
        LOGGER.info("recover triggered");
    }

    @Recover
    public void recover(Exception e, Long id) throws Exception {
        LOGGER.info("retry failure");
    }
}

Here's the class with the caller of the function:

@RestController
@RequestMapping("/orderRequests")
@Api(description = "orders API")
public class OrderRequestController {

    private static final Logger LOGGER = LoggerFactory.getLogger(OrderRequestController.class);

    private final OrderRequestDelegate orderRequestDelegate;

    @Autowired
    public OrderRequestController(OrderRequestDelegate orderRequestDelegate) {
        this.orderRequestDelegate = orderRequestDelegate;
    }

    //...  

    @ApiOperation(value="test function")
    @RequestMapping(method = RequestMethod.GET)
    public String get() {
        orderRequestDelegate.processItem("100", "abc");
        return String.format("Worked");
    }
}

And the Application class that includes the @EnableRetry annotation:

@SpringBootApplication
@EnableRetry
public class FulfillmentApplication extends SpringBootServletInitializer {

    private static final Logger LOGGER = LoggerFactory.getLogger(FulfillmentApplication.class);

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(FulfillmentApplication.class);
    }

    public static void main(String[] args) {
        LOGGER.debug("Starting Spring application main...");
        SpringApplication.run(FulfillmentApplication.class, args);
    }
}

Here's the stacktrace when I run the @Retryable function:

2017-01-27 12:58:21.918  INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate      : Tried in retryable
2017-01-27 12:58:22.022  INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate      : Tried in retryable
2017-01-27 12:58:22.129  INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate      : Tried in retryable
2017-01-27 12:58:22.231  INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate      : Tried in retryable
2017-01-27 12:58:22.336  INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate      : Tried in retryable
2017-01-27 12:58:22.352 ERROR 93294 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method; nested exception is javax.persistence.NoResultException] with root cause

javax.persistence.NoResultException: null
    at com.cfa.fulfillmentApi.delegate.OrderRequestDelegate.processItem(OrderRequestDelegate.java:44) ~[classes/:na]
    at com.cfa.fulfillmentApi.delegate.OrderRequestDelegate$$FastClassBySpringCGLIB$$f297a63a.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.retry.interceptor.RetryOperationsInterceptor$1.doWithRetry(RetryOperationsInterceptor.java:74) ~[spring-retry-1.1.2.RELEASE.jar:na]
    at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:263) ~[spring-retry-1.1.2.RELEASE.jar:na]
    at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:168) ~[spring-retry-1.1.2.RELEASE.jar:na]
    at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:98) ~[spring-retry-1.1.2.RELEASE.jar:na]
    at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:118) ~[spring-retry-1.1.2.RELEASE.jar:na]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at com.cfa.fulfillmentApi.delegate.OrderRequestDelegate$$EnhancerBySpringCGLIB$$44ec8aa9.processItem(<generated>) ~[classes/:na]
    at com.cfa.fulfillmentApi.controller.OrderRequestController.get(OrderRequestController.java:45) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_112]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_112]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_112]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_112]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:220) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55) ~[spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:105) ~[spring-boot-actuator-1.4.3.RELEASE.jar:1.4.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:89) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106) ~[spring-boot-actuator-1.4.3.RELEASE.jar:1.4.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:784) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_112]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_112]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.6.jar:8.5.6]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_112]

Looks Like you just missed the basic part like i did.

The method annotated with @Recover should take The same type of argument (and optional Throwable or its subclass typed argument). Beside that the The return type should also be the same.

Here is how your recover method should look like to be fired after the retry exhausted.

@Component
public static class Foo {

    @Retryable(include=NoResultException.class, backoff = `@Backoff(delay = 100, maxDelay = 101), maxAttempts = 5)`
    public void out(String foo) {
        System.out.println(foo);
        if (foo.equals("foo")) {
            throw new NoResultException();
        }
        else {
            throw new IllegalStateException();
        }
    }

    @Recover
    public void connectionException(NoResultException e, String foo) {
        System.out.println("Retry failure");
    }

    @Recover
    public void connectionException(Exception e, String foo) throws Exception {
        System.out.println("Retry failure");
        throw e;
    }

}

Here's the complete app from that answer, modified to be functionally equivalent to yours; if you still can't figure out what's wrong, edit your question with complete configuration and a debug log.

@SpringBootApplication
@EnableRetry
public class So38601998Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(So38601998Application.class, args);
        Foo bean = context.getBean(Foo.class);
        try {
            bean.out("foo");
            System.out.println("Recovered");
        }
        catch (Exception e) {
            System.out.println("Not recovered: " + e);
        }
        try {
            bean.out("bar");
        }
        catch (Exception e) {
            System.out.println("Not recovered: " + e);
        }
    }


    @Component
    public static class Foo {

        @Retryable(include=NoResultException.class, backoff = @Backoff(delay = 100, maxDelay = 101), maxAttempts = 5)
        public void out(String foo) {
            System.out.println(foo);
            if (foo.equals("foo")) {
                throw new NoResultException();
            }
            else {
                throw new IllegalStateException();
            }
        }

        @Recover
        public void connectionException(NoResultException e) {
            System.out.println("Retry failure");
        }

        @Recover
        public void connectionException(Exception e) throws Exception {
            System.out.println("Retry failure");
            throw e;
        }

    }

}

Results (with DEBUG logging for osretry )

14:16:25.803 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=0
foo
14:16:25.913 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=1
14:16:25.914 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=1
foo
14:16:26.017 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=2
14:16:26.017 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=2
foo
14:16:26.121 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=3
14:16:26.121 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=3
foo
14:16:26.223 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=4
14:16:26.223 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=4
foo
14:16:26.224 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=5
14:16:26.224 [main] DEBUG o.s.retry.support.RetryTemplate - Retry failed last attempt: count=5
Retry failure
Recovered
14:16:26.224 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=0
bar
14:16:26.225 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=1
14:16:26.225 [main] DEBUG o.s.retry.support.RetryTemplate - Retry failed last attempt: count=1
Retry failure
Not recovered: java.lang.IllegalStateException

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM