I've got a prototype bean implementing Runnable that has to retry its run-method and do something if the max retry cap is reached. Now I have the Problem that the recover method seems to be always invoked from the same spring bean not from the corresponding instance.
This is my code so far:
RetryableRunnable
@Slf4j
@AllArgsConstructor
public class RetryableRunnable implements Runnable {
private final RetryDemoService retryDemoService;
private final Status someStatus;
@Override
@Retryable(
value = { RuntimeException.class },
maxAttempts = 2,
backoff = @Backoff(delay = 2000))
public void run() {
log.info( "+++ RetryableRunnable executed! +++" );
retryDemoService.demoRun();
}
@Recover
private void recover() {
retryDemoService.demoRecover();
log.info( String.valueOf( someStatus ) );
}
}
Config
@Configuration
@AllArgsConstructor
@EnableRetry(proxyTargetClass = true)
public class RetryDemoConfig {
private final RetryDemoService retryDemoService;
@Bean
@Scope( "prototype" )
public RetryableRunnable retryableRunnable(Status status) {
return new RetryableRunnable( retryDemoService, status );
}
}
Service
@Service
@Slf4j
public class RetryDemoService {
void demoRun() {
log.info( "+++ Run! +++" );
}
void demoRecover() {
log.info( "+++ Recover! +++" );
}
}
Status Enum
public enum Status {
STATUS1, STATUS2
}
Test to show the problem
@RunWith( SpringRunner.class )
@SpringBootTest
public class RetryableRunnableTest {
@Autowired
private BeanFactory beanFactory;
@MockBean
RetryDemoService retryDemoService;
@Test
public void retrieableRunnableIsRetriedOnlyThreeTimesAndRecoverMethodIsRun() throws InterruptedException {
RetryableRunnable testInstance1 = beanFactory.getBean( RetryableRunnable.class, Status.STATUS1 );
RetryableRunnable testInstance2 = beanFactory.getBean( RetryableRunnable.class, Status.STATUS2 );
doThrow( new RuntimeException() )
.doThrow( new RuntimeException() )
.doThrow( new RuntimeException() )
.when( retryDemoService ).demoRun();
Thread thread1 = new Thread( testInstance1 );
thread1.start();
thread1.join();
Thread thread2 = new Thread( testInstance2 );
thread2.start();
thread2.join();
}
}
Now the output of the log is:
+++ RetryableRunnable executed! +++
+++ RetryableRunnable executed! +++
STATUS1
+++ RetryableRunnable executed! +++
+++ RetryableRunnable executed! +++
STATUS1
While it should be:
+++ RetryableRunnable executed! +++
+++ RetryableRunnable executed! +++
STATUS1
+++ RetryableRunnable executed! +++
+++ RetryableRunnable executed! +++
STATUS2
When I debug this test-method the recover method is invoked by RetryRunnable@3053 first time AND second time!
Is this a bug or am I missing the understanding of a concept? What can I do to solve this problem and invoke the corresponding prototype-bean "Status"-field?