Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support custom RetryConfiguration.getOrder() via @EnableRetry like @EnableAsync #22

Closed
quaff opened this issue Jan 6, 2015 · 15 comments · Fixed by #333
Closed

support custom RetryConfiguration.getOrder() via @EnableRetry like @EnableAsync #22

quaff opened this issue Jan 6, 2015 · 15 comments · Fixed by #333
Milestone

Comments

@quaff
Copy link
Contributor

quaff commented Jan 6, 2015

@EnableRetry(order = -1)
@Configuration
public class RetryConfiguration {

}

configure @retryable before @transactional, so we can handle transaction with stateless @retryable, is stateful necessary anymore?

@headstar
Copy link

Is it correct to say that the transactional advisor and retryable advisor are unordered in the snippet below? (using @EnableRetry to configure retries).

@Transactional
@Retryable
@Service
public class FooService {
}

@quaff
Copy link
Contributor Author

quaff commented May 14, 2015

Yes, you can do this

<tx:annotation-driven order="0"/>
@Configuration
public class RetryConfiguration extends
        org.springframework.retry.annotation.RetryConfiguration {

    @Override
    public int getOrder() {
        return -1;
    }

}

@headstar
Copy link

Ok, thanks.

@aartigao
Copy link

Hey, I'm looking for this feature. Are there any plans on implement it?

@quaff
Copy link
Contributor Author

quaff commented Aug 2, 2016

ping

@DieterVDW
Copy link

Pong!

Is this project still being maintained?

@ghost
Copy link

ghost commented Feb 14, 2017

this feature would be very nice to handle @transactional

@yoorick
Copy link

yoorick commented Nov 22, 2017

+1 for this feature.

We have multiple advisors in our project, and a MethodInvocation usually consists of a chain of two or more MethodInterceptors, and a particular order of them is important.

Now we have to use an approach similar to what @quaff showed above.

@wtritch
Copy link

wtritch commented Jun 6, 2018

In case others are still having this issue, we ran into a problem using a @Backoff annotation in a @Retryable @Transactional-annotated method. The @Backoff annotation includes an @Import(RetryConfiguration.class) which leads to double-registering retry AOP Advice (one for the class extending RetryConfiguration, and one for the imported RetryConfiguration.)

After some mucking around with Spring's configuration loading we decided on manually setting the RetryConfiguration order in a @PostConstruct which needs to be executed PRIOR to instantiating any advised beans. (Once a bean is advised the advice order is locked.)

@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
@EnableRetry
public class OrderRetryConfiguration {

    @Autowired
    public RetryConfiguration retryConfiguration;

    @PostConstruct
    public void postConstruct() {
        this.retryConfiguration.setOrder(Ordered.LOWEST_PRECEDENCE - 1);
    }
}

@philippthiele
Copy link

philippthiele commented Feb 4, 2022

In case others are still having this issue, we ran into a problem using a @Backoff annotation in a @Retryable @Transactional-annotated method. The @Backoff annotation includes an @Import(RetryConfiguration.class) which leads to double-registering retry AOP Advice (one for the class extending RetryConfiguration, and one for the imported RetryConfiguration.)

After some mucking around with Spring's configuration loading we decided on manually setting the RetryConfiguration order in a @PostConstruct which needs to be executed PRIOR to instantiating any advised beans. (Once a bean is advised the advice order is locked.)

@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
@EnableRetry
public class OrderRetryConfiguration {

    @Autowired
    public RetryConfiguration retryConfiguration;

    @PostConstruct
    public void postConstruct() {
        this.retryConfiguration.setOrder(Ordered.LOWEST_PRECEDENCE - 1);
    }
}

@wtritch
You seem to be correct, using backoff breaks @retryable in combination with @transactional. The Configuration you linked above does not fix that for me though.

@flozano
Copy link

flozano commented Feb 20, 2023

This issue looks important, any other workaround?

right now I'm reverting to having a service decorator with manual handling of retries with retryTemplate, which is far from ideal.

@quaff
Copy link
Contributor Author

quaff commented Feb 21, 2023

@garyrussell Could you take a look at this?

quaff added a commit to quaff/spring-retry that referenced this issue Feb 21, 2023
@artembilan artembilan added this to the 2.0.1 milestone Feb 21, 2023
artembilan pushed a commit that referenced this issue Feb 24, 2023
Fixes #22

Configure `@Retryable` before `@Transactional`, so we can handle transaction with stateless retries
@frankjkelly
Copy link

Interesting - for those of use waiting to go to Spring Retry 2.0.0 what is the advice to get correct operation of code like the following

    @Retryable(backoff = @Backoff(100), exclude = {EntityNotFoundException.class, IllegalArgumentException.class,
            IllegalStateException.class})
    @Transactional
public void doSomething() {

}

It sounds like precedence wise we want Retry logic to have higher precedence in AOP?

@quaff
Copy link
Contributor Author

quaff commented Mar 14, 2023

Interesting - for those of use waiting to go to Spring Retry 2.0.0 what is the advice to get correct operation of code like the following

    @Retryable(backoff = @Backoff(100), exclude = {EntityNotFoundException.class, IllegalArgumentException.class,
            IllegalStateException.class})
    @Transactional
public void doSomething() {

}

It sounds like precedence wise we want Retry logic to have higher precedence in AOP?

order value of EnableRetry should less than EnableTransactionManagement, like this

@EnableTransactionManagement(order = 0)
@EnableRetry(order = -1)

@artembilan
Copy link
Member

@quaff ,

you show the configuration exactly for a new upcoming version.
For an old one this should work:

		@Bean
		static BeanPostProcessor retryConfigurationPostProcessor() {
			return new BeanPostProcessor() {
				@Override
				public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
					if (bean instanceof RetryConfiguration) {
						((RetryConfiguration) bean).setOrder(Ordered.LOWEST_PRECEDENCE - 1);
					}
					return bean;
				}
			};
		}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants