2222import java .nio .file .AccessDeniedException ;
2323import java .time .Duration ;
2424import java .util .Properties ;
25+ import java .util .concurrent .CompletableFuture ;
26+ import java .util .concurrent .CompletionException ;
2527import java .util .concurrent .atomic .AtomicInteger ;
2628
2729import org .aopalliance .intercept .MethodInterceptor ;
4446import org .springframework .resilience .annotation .Retryable ;
4547import org .springframework .resilience .retry .MethodRetrySpec ;
4648import org .springframework .resilience .retry .SimpleRetryInterceptor ;
49+ import org .springframework .scheduling .annotation .Async ;
50+ import org .springframework .scheduling .annotation .EnableAsync ;
4751
4852import static org .assertj .core .api .Assertions .assertThat ;
53+ import static org .assertj .core .api .Assertions .assertThatExceptionOfType ;
4954import static org .assertj .core .api .Assertions .assertThatIOException ;
5055import static org .assertj .core .api .Assertions .assertThatRuntimeException ;
5156
@@ -265,11 +270,11 @@ void withPostProcessorForClassWithZeroAttempts() {
265270@ Test
266271void withEnableAnnotation () throws Exception {
267272AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext ();
268- ctx .registerBeanDefinition ("bean" , new RootBeanDefinition (DoubleAnnotatedBean .class ));
273+ ctx .registerBeanDefinition ("bean" , new RootBeanDefinition (ConcurrencyLimitAnnotatedBean .class ));
269274ctx .registerBeanDefinition ("config" , new RootBeanDefinition (EnablingConfig .class ));
270275ctx .refresh ();
271- DoubleAnnotatedBean proxy = ctx .getBean (DoubleAnnotatedBean .class );
272- DoubleAnnotatedBean target = (DoubleAnnotatedBean ) AopProxyUtils .getSingletonTarget (proxy );
276+ ConcurrencyLimitAnnotatedBean proxy = ctx .getBean (ConcurrencyLimitAnnotatedBean .class );
277+ ConcurrencyLimitAnnotatedBean target = (ConcurrencyLimitAnnotatedBean ) AopProxyUtils .getSingletonTarget (proxy );
273278
274279Thread thread = new Thread (() -> assertThatIOException ().isThrownBy (proxy ::retryOperation ));
275280thread .start ();
@@ -279,6 +284,20 @@ void withEnableAnnotation() throws Exception {
279284assertThat (target .threadChange ).hasValue (2 );
280285}
281286
287+ @ Test
288+ void withAsyncAnnotation () {
289+ AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext ();
290+ ctx .registerBeanDefinition ("bean" , new RootBeanDefinition (AsyncAnnotatedBean .class ));
291+ ctx .registerBeanDefinition ("config" , new RootBeanDefinition (EnablingConfigWithAsync .class ));
292+ ctx .refresh ();
293+ AsyncAnnotatedBean proxy = ctx .getBean (AsyncAnnotatedBean .class );
294+ AsyncAnnotatedBean target = (AsyncAnnotatedBean ) AopProxyUtils .getSingletonTarget (proxy );
295+
296+ assertThatExceptionOfType (CompletionException .class ).isThrownBy (() -> proxy .retryOperation ().join ())
297+ .withCauseInstanceOf (IllegalStateException .class );
298+ assertThat (target .counter ).hasValue (3 );
299+ }
300+
282301
283302static class NonAnnotatedBean implements PlainInterface {
284303
@@ -392,7 +411,7 @@ public void overrideOperation() throws IOException {
392411}
393412
394413
395- static class DoubleAnnotatedBean {
414+ static class ConcurrencyLimitAnnotatedBean {
396415
397416AtomicInteger current = new AtomicInteger ();
398417
@@ -419,8 +438,26 @@ public void retryOperation() throws IOException, InterruptedException {
419438}
420439
421440
441+ static class AsyncAnnotatedBean {
442+
443+ AtomicInteger counter = new AtomicInteger ();
444+
445+ @ Async
446+ @ Retryable (maxAttempts = 2 , delay = 10 )
447+ public CompletableFuture <Void > retryOperation () {
448+ throw new IllegalStateException (Integer .toString (counter .incrementAndGet ()));
449+ }
450+ }
451+
452+
422453@ EnableResilientMethods
423454static class EnablingConfig {
424455}
425456
457+
458+ @ EnableAsync
459+ @ EnableResilientMethods
460+ static class EnablingConfigWithAsync {
461+ }
462+
426463}
0 commit comments