diff --git a/pom.xml b/pom.xml index 5e703b4bc1..055b108141 100644 --- a/pom.xml +++ b/pom.xml @@ -826,6 +826,7 @@ spring-reactive-modules spring-remoting-modules spring-scheduling + spring-scheduling-2 spring-security-modules spring-shell spring-soap @@ -1074,6 +1075,7 @@ spring-reactive-modules spring-remoting-modules spring-scheduling + spring-scheduling-2 spring-security-modules spring-shell spring-soap diff --git a/spring-scheduling-2/README.md b/spring-scheduling-2/README.md new file mode 100644 index 0000000000..bc1911b396 --- /dev/null +++ b/spring-scheduling-2/README.md @@ -0,0 +1 @@ +### Relevant articles: \ No newline at end of file diff --git a/spring-scheduling-2/pom.xml b/spring-scheduling-2/pom.xml new file mode 100644 index 0000000000..9c69758ed0 --- /dev/null +++ b/spring-scheduling-2/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + spring-scheduling-2 + 0.1-SNAPSHOT + spring-scheduling-2 + jar + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../parent-boot-3 + + + + + org.springframework.boot + spring-boot-starter-web + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + repackage + none + + + + + + + \ No newline at end of file diff --git a/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/DelayedNotificationScheduler.java b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/DelayedNotificationScheduler.java new file mode 100644 index 0000000000..91ed9beffc --- /dev/null +++ b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/DelayedNotificationScheduler.java @@ -0,0 +1,22 @@ +package com.baeldung.disablingscheduledtasks; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Scheduled; + +public class DelayedNotificationScheduler { + + private static final Logger logger = LoggerFactory.getLogger(DelayedNotificationScheduler.class); + + private NotificationService notificationService; + + public DelayedNotificationScheduler(NotificationService notificationService) { + this.notificationService = notificationService; + } + + @Scheduled(fixedDelayString = "${notification.send.out.delay}", initialDelayString = "${notification.send.out.initial.delay}") + public void attemptSendingOutDelayedNotifications() { + logger.info("Scheduled notifications send out attempt"); + notificationService.sendOutDelayedNotifications(); + } +} \ No newline at end of file diff --git a/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/Notification.java b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/Notification.java new file mode 100644 index 0000000000..01ed80395e --- /dev/null +++ b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/Notification.java @@ -0,0 +1,31 @@ +package com.baeldung.disablingscheduledtasks; + +import java.time.Clock; +import java.time.ZonedDateTime; +import java.util.UUID; + +public class Notification { + + private UUID id = UUID.randomUUID(); + private boolean isSentOut = false; + private ZonedDateTime sendOutTime; + + public Notification(ZonedDateTime sendOutTime) { + this.sendOutTime = sendOutTime; + } + + public void sendOut(Clock clock) { + ZonedDateTime now = ZonedDateTime.now(clock); + if (now.isAfter(sendOutTime)) { + isSentOut = true; + } + } + + public UUID getId() { + return id; + } + + public boolean isSentOut() { + return isSentOut; + } +} \ No newline at end of file diff --git a/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/NotificationRepository.java b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/NotificationRepository.java new file mode 100644 index 0000000000..08fe8c830d --- /dev/null +++ b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/NotificationRepository.java @@ -0,0 +1,30 @@ +package com.baeldung.disablingscheduledtasks; + +import java.util.Collection; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.UUID; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.stream.Collectors; + +public class NotificationRepository { + + private Collection notifications = new ConcurrentLinkedQueue<>(); + + public Notification findById(UUID notificationId) { + return notifications.stream() + .filter(n -> notificationId.equals(n.getId())) + .findFirst() + .orElseThrow(NoSuchElementException::new); + } + + public List findAllAwaitingSendOut() { + return notifications.stream() + .filter(notification -> !notification.isSentOut()) + .collect(Collectors.toList()); + } + + public void save(Notification notification) { + notifications.add(notification); + } +} \ No newline at end of file diff --git a/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/NotificationService.java b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/NotificationService.java new file mode 100644 index 0000000000..3451a05cbe --- /dev/null +++ b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/NotificationService.java @@ -0,0 +1,26 @@ +package com.baeldung.disablingscheduledtasks; + +import java.time.Clock; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NotificationService { + + private static final Logger logger = LoggerFactory.getLogger(NotificationService.class); + + private NotificationRepository notificationRepository; + private Clock clock; + + public NotificationService(NotificationRepository notificationRepository, Clock clock) { + this.notificationRepository = notificationRepository; + this.clock = clock; + } + + public void sendOutDelayedNotifications() { + logger.info("Sending out delayed notifications"); + List notifications = notificationRepository.findAllAwaitingSendOut(); + notifications.forEach(notification -> notification.sendOut(clock)); + } +} \ No newline at end of file diff --git a/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithprofile/ApplicationConfig.java b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithprofile/ApplicationConfig.java new file mode 100644 index 0000000000..19a69840ff --- /dev/null +++ b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithprofile/ApplicationConfig.java @@ -0,0 +1,34 @@ +package com.baeldung.disablingscheduledtasks.config.disablewithprofile; + +import java.time.Clock; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.baeldung.disablingscheduledtasks.DelayedNotificationScheduler; +import com.baeldung.disablingscheduledtasks.NotificationRepository; +import com.baeldung.disablingscheduledtasks.NotificationService; + +@Configuration +public class ApplicationConfig { + + @Bean + public Clock clock() { + return Clock.systemUTC(); + } + + @Bean + public NotificationRepository notificationRepository() { + return new NotificationRepository(); + } + + @Bean + public NotificationService notificationService(NotificationRepository notificationRepository, Clock clock) { + return new NotificationService(notificationRepository, clock); + } + + @Bean + public DelayedNotificationScheduler delayedNotificationScheduler(NotificationService notificationService) { + return new DelayedNotificationScheduler(notificationService); + } +} \ No newline at end of file diff --git a/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithprofile/SchedulingConfig.java b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithprofile/SchedulingConfig.java new file mode 100644 index 0000000000..6461b9273d --- /dev/null +++ b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithprofile/SchedulingConfig.java @@ -0,0 +1,12 @@ +package com.baeldung.disablingscheduledtasks.config.disablewithprofile; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +@Profile("!integrationTest") +public class SchedulingConfig { + +} \ No newline at end of file diff --git a/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithproperty/ApplicationConfig.java b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithproperty/ApplicationConfig.java new file mode 100644 index 0000000000..8b006428d2 --- /dev/null +++ b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithproperty/ApplicationConfig.java @@ -0,0 +1,34 @@ +package com.baeldung.disablingscheduledtasks.config.disablewithproperty; + +import java.time.Clock; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.baeldung.disablingscheduledtasks.DelayedNotificationScheduler; +import com.baeldung.disablingscheduledtasks.NotificationRepository; +import com.baeldung.disablingscheduledtasks.NotificationService; + +@Configuration +public class ApplicationConfig { + + @Bean + public Clock clock() { + return Clock.systemUTC(); + } + + @Bean + public NotificationRepository notificationRepository() { + return new NotificationRepository(); + } + + @Bean + public NotificationService notificationService(NotificationRepository notificationRepository, Clock clock) { + return new NotificationService(notificationRepository, clock); + } + + @Bean + public DelayedNotificationScheduler delayedNotificationScheduler(NotificationService notificationService) { + return new DelayedNotificationScheduler(notificationService); + } +} \ No newline at end of file diff --git a/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithproperty/SchedulingConfig.java b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithproperty/SchedulingConfig.java new file mode 100644 index 0000000000..2b85dbfcef --- /dev/null +++ b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/disablewithproperty/SchedulingConfig.java @@ -0,0 +1,12 @@ +package com.baeldung.disablingscheduledtasks.config.disablewithproperty; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +@ConditionalOnProperty(value = "scheduling.enabled", havingValue = "true", matchIfMissing = true) +public class SchedulingConfig { + +} \ No newline at end of file diff --git a/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/schedulingon/ApplicationConfig.java b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/schedulingon/ApplicationConfig.java new file mode 100644 index 0000000000..e0db118831 --- /dev/null +++ b/spring-scheduling-2/src/main/java/com/baeldung/disablingscheduledtasks/config/schedulingon/ApplicationConfig.java @@ -0,0 +1,36 @@ +package com.baeldung.disablingscheduledtasks.config.schedulingon; + +import java.time.Clock; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +import com.baeldung.disablingscheduledtasks.DelayedNotificationScheduler; +import com.baeldung.disablingscheduledtasks.NotificationRepository; +import com.baeldung.disablingscheduledtasks.NotificationService; + +@Configuration +@EnableScheduling +public class ApplicationConfig { + + @Bean + public Clock clock() { + return Clock.systemUTC(); + } + + @Bean + public NotificationRepository notificationRepository() { + return new NotificationRepository(); + } + + @Bean + public NotificationService notificationService(NotificationRepository notificationRepository, Clock clock) { + return new NotificationService(notificationRepository, clock); + } + + @Bean + public DelayedNotificationScheduler delayedNotificationScheduler(NotificationService notificationService) { + return new DelayedNotificationScheduler(notificationService); + } +} \ No newline at end of file diff --git a/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/disablewithprofile/DelayedNotificationSchedulerIntegrationTest.java b/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/disablewithprofile/DelayedNotificationSchedulerIntegrationTest.java new file mode 100644 index 0000000000..523950e48c --- /dev/null +++ b/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/disablewithprofile/DelayedNotificationSchedulerIntegrationTest.java @@ -0,0 +1,64 @@ +package com.baeldung.disablingscheduledtasks.disablewithprofile; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ActiveProfiles; + +import com.baeldung.disablingscheduledtasks.DelayedNotificationScheduler; +import com.baeldung.disablingscheduledtasks.Notification; +import com.baeldung.disablingscheduledtasks.NotificationRepository; +import com.baeldung.disablingscheduledtasks.config.disablewithprofile.ApplicationConfig; +import com.baeldung.disablingscheduledtasks.config.disablewithprofile.SchedulingConfig; + +@SpringBootTest( + classes = { ApplicationConfig.class, SchedulingConfig.class, SchedulerTestConfiguration.class }, + properties = { + "notification.send.out.delay: 10", + "notification.send.out.initial.delay: 0" + } +) +@ActiveProfiles("integrationTest") +public class DelayedNotificationSchedulerIntegrationTest { + + @Autowired + private Clock testClock; + + @Autowired + private NotificationRepository repository; + + @Autowired + private DelayedNotificationScheduler scheduler; + + @Test + public void whenTimeIsOverNotificationSendOutTime_thenItShouldBeSent() { + ZonedDateTime fiveMinutesAgo = ZonedDateTime.now(testClock).minusMinutes(5); + Notification notification = new Notification(fiveMinutesAgo); + repository.save(notification); + + scheduler.attemptSendingOutDelayedNotifications(); + + Notification processedNotification = repository.findById(notification.getId()); + assertTrue(processedNotification.isSentOut()); + } +} + +@TestConfiguration +class SchedulerTestConfiguration { + + @Bean + @Primary + public Clock testClock() { + return Clock.fixed(Instant.parse("2024-03-10T10:15:30.00Z"), ZoneId.systemDefault()); + } +} \ No newline at end of file diff --git a/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/disablewithproperty/DelayedNotificationSchedulerIntegrationTest.java b/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/disablewithproperty/DelayedNotificationSchedulerIntegrationTest.java new file mode 100644 index 0000000000..da3a061cfc --- /dev/null +++ b/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/disablewithproperty/DelayedNotificationSchedulerIntegrationTest.java @@ -0,0 +1,63 @@ +package com.baeldung.disablingscheduledtasks.disablewithproperty; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; + +import com.baeldung.disablingscheduledtasks.DelayedNotificationScheduler; +import com.baeldung.disablingscheduledtasks.Notification; +import com.baeldung.disablingscheduledtasks.NotificationRepository; +import com.baeldung.disablingscheduledtasks.config.disablewithproperty.ApplicationConfig; +import com.baeldung.disablingscheduledtasks.config.disablewithproperty.SchedulingConfig; + +@SpringBootTest( + classes = { ApplicationConfig.class, SchedulingConfig.class, SchedulerTestConfiguration.class }, + properties = { + "notification.send.out.delay: 10", + "notification.send.out.initial.delay: 0", + "scheduling.enabled: false" + } +) +public class DelayedNotificationSchedulerIntegrationTest { + + @Autowired + private Clock testClock; + + @Autowired + private NotificationRepository repository; + + @Autowired + private DelayedNotificationScheduler scheduler; + + @Test + public void whenTimeIsOverNotificationSendOutTime_thenItShouldBeSent() { + ZonedDateTime fiveMinutesAgo = ZonedDateTime.now(testClock).minusMinutes(5); + Notification notification = new Notification(fiveMinutesAgo); + repository.save(notification); + + scheduler.attemptSendingOutDelayedNotifications(); + + Notification processedNotification = repository.findById(notification.getId()); + assertTrue(processedNotification.isSentOut()); + } +} + +@TestConfiguration +class SchedulerTestConfiguration { + + @Bean + @Primary + public Clock testClock() { + return Clock.fixed(Instant.parse("2024-03-10T10:15:30.00Z"), ZoneId.systemDefault()); + } +} \ No newline at end of file diff --git a/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/longinitialdelay/DelayedNotificationSchedulerIntegrationTest.java b/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/longinitialdelay/DelayedNotificationSchedulerIntegrationTest.java new file mode 100644 index 0000000000..d67af13b9d --- /dev/null +++ b/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/longinitialdelay/DelayedNotificationSchedulerIntegrationTest.java @@ -0,0 +1,61 @@ +package com.baeldung.disablingscheduledtasks.longinitialdelay; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; + +import com.baeldung.disablingscheduledtasks.DelayedNotificationScheduler; +import com.baeldung.disablingscheduledtasks.Notification; +import com.baeldung.disablingscheduledtasks.NotificationRepository; +import com.baeldung.disablingscheduledtasks.config.schedulingon.ApplicationConfig; + +@SpringBootTest( + classes = { ApplicationConfig.class, SchedulerTestConfiguration.class }, + properties = { + "notification.send.out.delay: 10", + "notification.send.out.initial.delay: 60000" + } +) +public class DelayedNotificationSchedulerIntegrationTest { + + @Autowired + private Clock testClock; + + @Autowired + private NotificationRepository repository; + + @Autowired + private DelayedNotificationScheduler scheduler; + + @Test + public void whenTimeIsOverNotificationSendOutTime_thenItShouldBeSent() { + ZonedDateTime fiveMinutesAgo = ZonedDateTime.now(testClock).minusMinutes(5); + Notification notification = new Notification(fiveMinutesAgo); + repository.save(notification); + + scheduler.attemptSendingOutDelayedNotifications(); + + Notification processedNotification = repository.findById(notification.getId()); + assertTrue(processedNotification.isSentOut()); + } +} + +@TestConfiguration +class SchedulerTestConfiguration { + + @Bean + @Primary + public Clock testClock() { + return Clock.fixed(Instant.parse("2024-03-10T10:15:30.00Z"), ZoneId.systemDefault()); + } +} \ No newline at end of file diff --git a/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/schedulingon/DelayedNotificationSchedulerIntegrationTest.java b/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/schedulingon/DelayedNotificationSchedulerIntegrationTest.java new file mode 100644 index 0000000000..eb351ee2d1 --- /dev/null +++ b/spring-scheduling-2/src/test/java/com/baeldung/disablingscheduledtasks/schedulingon/DelayedNotificationSchedulerIntegrationTest.java @@ -0,0 +1,61 @@ +package com.baeldung.disablingscheduledtasks.schedulingon; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; + +import com.baeldung.disablingscheduledtasks.DelayedNotificationScheduler; +import com.baeldung.disablingscheduledtasks.Notification; +import com.baeldung.disablingscheduledtasks.NotificationRepository; +import com.baeldung.disablingscheduledtasks.config.schedulingon.ApplicationConfig; + +@SpringBootTest( + classes = { ApplicationConfig.class, SchedulerTestConfiguration.class }, + properties = { + "notification.send.out.delay: 10", + "notification.send.out.initial.delay: 0" + } +) +public class DelayedNotificationSchedulerIntegrationTest { + + @Autowired + private Clock testClock; + + @Autowired + private NotificationRepository repository; + + @Autowired + private DelayedNotificationScheduler scheduler; + + @Test + public void whenTimeIsOverNotificationSendOutTime_thenItShouldBeSent() { + ZonedDateTime fiveMinutesAgo = ZonedDateTime.now(testClock).minusMinutes(5); + Notification notification = new Notification(fiveMinutesAgo); + repository.save(notification); + + scheduler.attemptSendingOutDelayedNotifications(); + + Notification processedNotification = repository.findById(notification.getId()); + assertTrue(processedNotification.isSentOut()); + } +} + +@TestConfiguration +class SchedulerTestConfiguration { + + @Bean + @Primary + public Clock testClock() { + return Clock.fixed(Instant.parse("2024-03-10T10:15:30.00Z"), ZoneId.systemDefault()); + } +} \ No newline at end of file