Repository: kagkarlsson/db-scheduler (java)

Issue:
More flexibility during auto configuration process
Hi guys,

Is possible to have the annotation @ConditionalOnMissingBean on all beans declared in auto configuration class DbSchedulerAutoConfiguration? In my case I need to override the DbSchedulerStarter bean adding my logic.

Thanks,
Michele


Discussion:
Curious question, what logic is it you want to add?
I'm using Apache Camel and I would like to start the scheduler only when the status of some routes is available. Now I solved my problem looping on a method that check if the status of a specific route is available. But I would listen to a specific event of the Apache Camel framework and then start the scheduler. That's all. Thank you.
Ok, sounds like an ok use-case. Working on something else atm, but PRs are welcome if needed soon :) 

Patch:
diff --git a/db-scheduler-boot-starter/src/main/java/com/github/kagkarlsson/scheduler/boot/autoconfigure/DbSchedulerAutoConfiguration.java b/db-scheduler-boot-starter/src/main/java/com/github/kagkarlsson/scheduler/boot/autoconfigure/DbSchedulerAutoConfiguration.java
--- a/db-scheduler-boot-starter/src/main/java/com/github/kagkarlsson/scheduler/boot/autoconfigure/DbSchedulerAutoConfiguration.java
+++ b/db-scheduler-boot-starter/src/main/java/com/github/kagkarlsson/scheduler/boot/autoconfigure/DbSchedulerAutoConfiguration.java
@@ -136,6 +136,7 @@ public HealthIndicator dbScheduler(Scheduler scheduler) {
     }
 
     @ConditionalOnBean(Scheduler.class)
+    @ConditionalOnMissingBean
     @Bean
     public DbSchedulerStarter dbSchedulerStarter(Scheduler scheduler) {
         if (config.isDelayStartupUntilContextReady()) {


Test patch:
diff --git a/db-scheduler-boot-starter/src/test/java/com/github/kagkarlsson/scheduler/boot/autoconfigure/DbSchedulerAutoConfigurationTest.java b/db-scheduler-boot-starter/src/test/java/com/github/kagkarlsson/scheduler/boot/autoconfigure/DbSchedulerAutoConfigurationTest.java
--- a/db-scheduler-boot-starter/src/test/java/com/github/kagkarlsson/scheduler/boot/autoconfigure/DbSchedulerAutoConfigurationTest.java
+++ b/db-scheduler-boot-starter/src/test/java/com/github/kagkarlsson/scheduler/boot/autoconfigure/DbSchedulerAutoConfigurationTest.java
@@ -5,11 +5,17 @@
 
 import com.github.kagkarlsson.scheduler.Scheduler;
 import com.github.kagkarlsson.scheduler.boot.actuator.DbSchedulerHealthIndicator;
+import com.github.kagkarlsson.scheduler.boot.config.DbSchedulerStarter;
+import com.github.kagkarlsson.scheduler.boot.config.startup.AbstractSchedulerStarter;
+import com.github.kagkarlsson.scheduler.boot.config.startup.ContextReadyStart;
+import com.github.kagkarlsson.scheduler.boot.config.startup.ImmediateStart;
 import com.github.kagkarlsson.scheduler.task.Task;
 import com.github.kagkarlsson.scheduler.task.helper.Tasks;
+import com.github.kagkarlsson.scheduler.task.schedule.Schedule;
 import com.google.common.collect.ImmutableList;
 import java.util.Objects;
 import javax.sql.DataSource;
+import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
@@ -20,8 +26,6 @@
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
-import org.junit.jupiter.api.Test;
-
 
 public class DbSchedulerAutoConfigurationTest {
     private static final Logger log = LoggerFactory.getLogger(DbSchedulerAutoConfigurationTest.class);
@@ -91,6 +95,47 @@ public void it_should_skip_autoconfiguration_if_explicitly_disabled() {
             });
     }
 
+    @Test
+    public void it_should_start_as_soon_as_possible() {
+        ctxRunner
+            .withPropertyValues("db-scheduler.delay-startup-until-context-ready=false")
+            .run((AssertableApplicationContext ctx) -> {
+                assertThat(ctx).hasSingleBean(Scheduler.class);
+
+                assertThat(ctx).hasSingleBean(DbSchedulerStarter.class);
+                assertThat(ctx).hasSingleBean(ImmediateStart.class);
+                assertThat(ctx).doesNotHaveBean(ContextReadyStart.class);
+
+            });
+    }
+
+    @Test
+    public void it_should_start_when_the_context_is_ready() {
+        ctxRunner
+            .withPropertyValues("db-scheduler.delay-startup-until-context-ready=true")
+            .run((AssertableApplicationContext ctx) -> {
+                assertThat(ctx).hasSingleBean(Scheduler.class);
+
+                assertThat(ctx).hasSingleBean(DbSchedulerStarter.class);
+                assertThat(ctx).hasSingleBean(ContextReadyStart.class);
+                assertThat(ctx).doesNotHaveBean(ImmediateStart.class);
+
+            });
+    }
+
+    @Test
+    public void it_should_support_custom_starting_strategies() {
+        ctxRunner
+            .withUserConfiguration(CustomStarterConfiguration.class)
+            .run((AssertableApplicationContext ctx) -> {
+                assertThat(ctx).hasSingleBean(Scheduler.class);
+
+                assertThat(ctx).hasSingleBean(DbSchedulerStarter.class);
+                assertThat(ctx).doesNotHaveBean(ContextReadyStart.class);
+                assertThat(ctx).doesNotHaveBean(ImmediateStart.class);
+            });
+    }
+
     @Configuration
     static class SingleTaskConfiguration {
         @Bean
@@ -117,6 +162,28 @@ Task<String> thirdTask() {
         }
     }
 
+    @Configuration
+    static class CustomStarterConfiguration extends SingleTaskConfiguration {
+        @Bean
+        DbSchedulerStarter someCustomStarter(Scheduler scheduler) {
+            return new SomeCustomStarter(scheduler);
+        }
+
+        static class SomeCustomStarter extends AbstractSchedulerStarter {
+            SomeCustomStarter(Scheduler scheduler) {
+                super(scheduler);
+
+                try {
+                    log.info("Thinking 5 seconds before starting the scheduler");
+                    Thread.sleep(5_000);
+                    doStart();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
     private static Task<String> namedStringTask(String name) {
         Objects.requireNonNull(name);