diff --git a/spring-scheduling/pom.xml b/spring-scheduling/pom.xml
index ece6a9aba7f2..e73c6118a06b 100644
--- a/spring-scheduling/pom.xml
+++ b/spring-scheduling/pom.xml
@@ -7,6 +7,18 @@
0.1-SNAPSHOT
jar
spring-scheduling
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 21
+ 21
+
+
+
+
com.baeldung
@@ -56,10 +68,21 @@
junit-vintage-engine
test
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
2.0.12
+ 4.0.2
diff --git a/spring-scheduling/src/main/java/com/baeldung/springretry/ExternalService.java b/spring-scheduling/src/main/java/com/baeldung/springretry/ExternalService.java
new file mode 100644
index 000000000000..8b493afc8429
--- /dev/null
+++ b/spring-scheduling/src/main/java/com/baeldung/springretry/ExternalService.java
@@ -0,0 +1,23 @@
+package com.baeldung.springretry;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.resilience.annotation.Retryable;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ExternalService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ExternalService.class);
+
+ private int attempt = 0;
+
+ @Retryable(maxRetries = 2, delay = 500)
+ public void callExternalApi() {
+
+ attempt++;
+ LOG.info("Attempt {} - Calling external API...", attempt);
+
+ throw new RuntimeException("Temporary connection failure!");
+ }
+}
\ No newline at end of file
diff --git a/spring-scheduling/src/main/java/com/baeldung/springretry/RetryEventListener.java b/spring-scheduling/src/main/java/com/baeldung/springretry/RetryEventListener.java
new file mode 100644
index 000000000000..cf0da4b4a8b8
--- /dev/null
+++ b/spring-scheduling/src/main/java/com/baeldung/springretry/RetryEventListener.java
@@ -0,0 +1,27 @@
+package com.baeldung.springretry;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.event.EventListener;
+import org.springframework.resilience.retry.MethodRetryEvent;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RetryEventListener {
+
+ private static final Logger log = LoggerFactory.getLogger(RetryEventListener.class);
+
+ @EventListener
+ public void onRetryEvent(MethodRetryEvent event) {
+ String methodName = event.getMethod()
+ .getName();
+ Throwable exception = event.getFailure();
+
+ if (event.isRetryAborted()) {
+ log.error("Retries exhausted for method '{}' after {} attempts. Final exception: {}", methodName, exception.getMessage());
+
+ } else {
+ log.warn("Retry failed for method '{}'. Exception: {}", methodName, exception.getMessage());
+ }
+ }
+}
diff --git a/spring-scheduling/src/test/java/com/baeldung/springretry/SpringRetryListenerIntegrationTest.java b/spring-scheduling/src/test/java/com/baeldung/springretry/SpringRetryListenerIntegrationTest.java
new file mode 100644
index 000000000000..c5f495e33548
--- /dev/null
+++ b/spring-scheduling/src/test/java/com/baeldung/springretry/SpringRetryListenerIntegrationTest.java
@@ -0,0 +1,22 @@
+package com.baeldung.springretry;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+public class SpringRetryListenerIntegrationTest {
+
+ @Autowired
+ private ExternalService externalService;
+
+ @Test
+ void givenFailingExternalService_whenCallExternalApi_thenShouldRetryMultipleTimesAndLogRetriesExhausted() {
+ assertThrows(RuntimeException.class, () -> {
+ externalService.callExternalApi();
+ });
+ }
+
+}
diff --git a/spring-scheduling/src/test/resources/logback-test.xml b/spring-scheduling/src/test/resources/logback-test.xml
index af8c372d9651..80306d0c64b5 100644
--- a/spring-scheduling/src/test/resources/logback-test.xml
+++ b/spring-scheduling/src/test/resources/logback-test.xml
@@ -1,6 +1,16 @@
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
-
+
+
+
+
+
+
\ No newline at end of file