I've started using the @Retryable annotation in my Spring Boot application (Spring Boot 2.7.18, JDK 21) and it works perfectly fine!
Below are some relevant extracts from the code:
@EnableRetry
@EnableTransactionManagement
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
@Service
public class MyService {
@Retryable(
retryFor = {LockAcquisitionException.class, SQLServerException.class},
maxAttempts = 5,
backoff = @Backoff(delay = 500),
listeners = "myRetryListener"
)
@Transactional
@Override
public void doSomething() throws MyException {
// Does something
}
}
public class MyRetryListener implements RetryListener {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
log.info("Retry open.");
return true;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
int attempt = context.getRetryCount();
if (throwable == null) {
log.info("Operation succeeded after {} attempts.", attempt);
} else {
log.info("Operation failed after {} attempts.", attempt);
}
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
log.warn("Inner retry {} of {} failed due to: {}", context.getRetryCount(), context.getAttribute("context.max-attempts"), throwable.getMessage());
}
}
HOWEVER, when I run an integration test for the application, although the retry mechanism works, it only retries once. I suspect I am missing some initialization in the test, but I cannot figure out what it is.
Has anyone experienced anything similar?
@SpringBootTest
@ActiveProfiles("test")
@EnableAutoConfiguration
@AutoConfigureMockMvc
class MyApplicationIntegrationTest {
}
The application writes some records to a MS SQL Server database, which I have simulated in test with an H2 in memory database. In the integration test I throw a SQLException via a 'BEFORE INSERT' trigger in the H2 table.
The output of the application is, as expected:
2025-01-29 12:05:14 INFO .MyRetryListener : Retry open.
2025-01-29 12:05:15 WARN SqlExceptionHelper : SQL Error: 50000, SQLState: S0001
2025-01-29 12:05:15 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025-01-29 12:05:15 WARN .MyRetryListener : Inner retry 1 of 5 failed due to: Could not persist entities
2025-01-29 12:05:15 WARN SqlExceptionHelper : SQL Error: 50000, SQLState: S0001
2025-01-29 12:05:15 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025-01-29 12:05:15 WARN .MyRetryListener : Inner retry 2 of 5 failed due to: Could not persist entities
2025-01-29 12:05:16 WARN SqlExceptionHelper : SQL Error: 50000, SQLState: S0001
2025-01-29 12:05:16 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025-01-29 12:05:16 WARN .MyRetryListener : Inner retry 3 of 5 failed due to: Could not persist entities
2025-01-29 12:05:16 WARN SqlExceptionHelper : SQL Error: 50000, SQLState: S0001
2025-01-29 12:05:16 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025-01-29 12:05:16 WARN .MyRetryListener : Inner retry 4 of 5 failed due to: Could not persist entities
2025-01-29 12:05:17 WARN SqlExceptionHelper : SQL Error: 50000, SQLState: S0001
2025-01-29 12:05:17 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025-01-29 12:05:17 WARN .MyRetryListener : Inner retry 5 of 5 failed due to: Could not persist entities
2025-01-29 12:05:17 INFO .MyRetryListener : Operation failed after 5 attempts.
while the output of the test is, sadly:
2025:01:29 12:12:37 INFO .MyRetryListener : Retry open.
2025:01:29 12:12:37 WARN TriggerImpl : Executing database trigger H2TriggerImpl: Simulated SQLException for testing
2025:01:29 12:12:37 WARN SqlExceptionHelper : SQL Error: 0, SQLState: null
2025:01:29 12:12:37 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025:01:29 12:12:37 INFO .AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
2025:01:29 12:12:38 WARN .MyRetryListener : Inner retry 1 of 5 failed due to: Could not persist entities
2025:01:29 12:12:38 INFO .MyRetryListener : Operation failed after 1 attempts.
I've started using the @Retryable annotation in my Spring Boot application (Spring Boot 2.7.18, JDK 21) and it works perfectly fine!
Below are some relevant extracts from the code:
@EnableRetry
@EnableTransactionManagement
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
@Service
public class MyService {
@Retryable(
retryFor = {LockAcquisitionException.class, SQLServerException.class},
maxAttempts = 5,
backoff = @Backoff(delay = 500),
listeners = "myRetryListener"
)
@Transactional
@Override
public void doSomething() throws MyException {
// Does something
}
}
public class MyRetryListener implements RetryListener {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
log.info("Retry open.");
return true;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
int attempt = context.getRetryCount();
if (throwable == null) {
log.info("Operation succeeded after {} attempts.", attempt);
} else {
log.info("Operation failed after {} attempts.", attempt);
}
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
log.warn("Inner retry {} of {} failed due to: {}", context.getRetryCount(), context.getAttribute("context.max-attempts"), throwable.getMessage());
}
}
HOWEVER, when I run an integration test for the application, although the retry mechanism works, it only retries once. I suspect I am missing some initialization in the test, but I cannot figure out what it is.
Has anyone experienced anything similar?
@SpringBootTest
@ActiveProfiles("test")
@EnableAutoConfiguration
@AutoConfigureMockMvc
class MyApplicationIntegrationTest {
}
The application writes some records to a MS SQL Server database, which I have simulated in test with an H2 in memory database. In the integration test I throw a SQLException via a 'BEFORE INSERT' trigger in the H2 table.
The output of the application is, as expected:
2025-01-29 12:05:14 INFO .MyRetryListener : Retry open.
2025-01-29 12:05:15 WARN SqlExceptionHelper : SQL Error: 50000, SQLState: S0001
2025-01-29 12:05:15 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025-01-29 12:05:15 WARN .MyRetryListener : Inner retry 1 of 5 failed due to: Could not persist entities
2025-01-29 12:05:15 WARN SqlExceptionHelper : SQL Error: 50000, SQLState: S0001
2025-01-29 12:05:15 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025-01-29 12:05:15 WARN .MyRetryListener : Inner retry 2 of 5 failed due to: Could not persist entities
2025-01-29 12:05:16 WARN SqlExceptionHelper : SQL Error: 50000, SQLState: S0001
2025-01-29 12:05:16 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025-01-29 12:05:16 WARN .MyRetryListener : Inner retry 3 of 5 failed due to: Could not persist entities
2025-01-29 12:05:16 WARN SqlExceptionHelper : SQL Error: 50000, SQLState: S0001
2025-01-29 12:05:16 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025-01-29 12:05:16 WARN .MyRetryListener : Inner retry 4 of 5 failed due to: Could not persist entities
2025-01-29 12:05:17 WARN SqlExceptionHelper : SQL Error: 50000, SQLState: S0001
2025-01-29 12:05:17 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025-01-29 12:05:17 WARN .MyRetryListener : Inner retry 5 of 5 failed due to: Could not persist entities
2025-01-29 12:05:17 INFO .MyRetryListener : Operation failed after 5 attempts.
while the output of the test is, sadly:
2025:01:29 12:12:37 INFO .MyRetryListener : Retry open.
2025:01:29 12:12:37 WARN TriggerImpl : Executing database trigger H2TriggerImpl: Simulated SQLException for testing
2025:01:29 12:12:37 WARN SqlExceptionHelper : SQL Error: 0, SQLState: null
2025:01:29 12:12:37 ERROR SqlExceptionHelper : Simulated SQLException for testing
2025:01:29 12:12:37 INFO .AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
2025:01:29 12:12:38 WARN .MyRetryListener : Inner retry 1 of 5 failed due to: Could not persist entities
2025:01:29 12:12:38 INFO .MyRetryListener : Operation failed after 1 attempts.
Share
Improve this question
asked Jan 29 at 12:23
GepGep
9283 gold badges16 silver badges33 bronze badges
4
|
2 Answers
Reset to default 1According to your configuration only these exceptions are retryable:
retryFor = {LockAcquisitionException.class, SQLServerException.class},
So, make sure that your test environment throws one of those. All other exceptions are not retryable.
I do not have enough stackoverflow points so I am responding via an answer.
Given that you have LockAcquisition
, I assume you are using a version column.
If you are using versioning, there are some additional annotations you might require depending on what type of locking approach you are taking.
For instance, for optimistic locking there's the annotation below where you can specify the exact lock type mode you want.
@Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
And also exceptions related to optimistic locking such as OptimisticLockException.class
, CannotAcquireLockException.class
, UnexpectedRollbackException.class
, etc based on your requirements..
If this isn't the case, let me know and I can try to help as I have PROD experience with having to implement retryable.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745298252a4621274.html
retryFor = {LockAcquisitionException.class, SQLServerException.class}
, but probably your test environment doesn't not throw those exceptions. Some other instead, which is not retryable. – Artem Bilan Commented Jan 31 at 15:42