From bc49474eece8214311d9c6e03e0b1f9519c515d3 Mon Sep 17 00:00:00 2001 From: Manyanda Chitimbo Date: Thu, 29 Aug 2019 23:33:34 +0200 Subject: [PATCH] feat(scheduler): add scheduler configuration and add support for clustering Fixes #3520 --- docs/src/main/asciidoc/scheduled-guide.adoc | 69 +++++++ .../deployment/SchedulerProcessor.java | 42 ++++- .../scheduler/test/NoDataSourceTest.java | 31 +++ extensions/scheduler/runtime/pom.xml | 4 + ...AgroalQuartzConnectionPoolingProvider.java | 50 +++++ .../scheduler/runtime/QuartzScheduler.java | 59 ++++-- .../runtime/SchedulerBuildTimeConfig.java | 88 +++++++++ .../runtime/SchedulerConfigHolder.java | 23 +++ .../runtime/SchedulerDeploymentRecorder.java | 7 + .../runtime/SchedulerRuntimeConfig.java | 29 +++ .../quarkus/scheduler/runtime/StoreType.java | 14 ++ .../main/resources/META-INF/persistence.xml | 2 + .../src/main/resources/application.properties | 6 + .../main/src/main/resources/import.sql | 178 ++++++++++++++++++ 14 files changed, 583 insertions(+), 19 deletions(-) create mode 100644 extensions/scheduler/deployment/src/test/java/io/quarkus/scheduler/test/NoDataSourceTest.java create mode 100644 extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/AgroalQuartzConnectionPoolingProvider.java create mode 100644 extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerBuildTimeConfig.java create mode 100644 extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerConfigHolder.java create mode 100644 extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerRuntimeConfig.java create mode 100644 extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/StoreType.java create mode 100644 integration-tests/main/src/main/resources/import.sql diff --git a/docs/src/main/asciidoc/scheduled-guide.adoc b/docs/src/main/asciidoc/scheduled-guide.adoc index a366bc75100e0..1f2316c3673d0 100644 --- a/docs/src/main/asciidoc/scheduled-guide.adoc +++ b/docs/src/main/asciidoc/scheduled-guide.adoc @@ -158,6 +158,75 @@ public class CountResourceTest { ---- 1. Ensure that the response contains `count` +== Scheduler configurations + +`quarkus.scheduler.instance-name`:: The instance name of the scheduler. ++ +Type: `java.lang.String` + +Defaults to: `DefaultQuartzScheduler` + + + +`quarkus.scheduler.store.misfire-threshold`:: The number of duration by which a trigger must have missed its next-fire-time, in order for it to be considered "misfired" and thus have its misfire instruction applied. ++ +Type: `java.time.Duration` + +Defaults to: `1m` + + + +`quarkus.scheduler.store.cluster-checking-interval`:: The frequency at which this instance "checks-in" with the other instances of the cluster .This affects the rate of detecting failed instances. ++ +Type: `java.time.Duration` + +Defaults to: `20s` + + + +`quarkus.scheduler.store.cluster-enabled`:: Enable cluster mode or not. This takes effect is the store type is `database-store`. ++ +Type: `java.lang.Boolean` + + + +`quarkus.scheduler.store.driver-delegate-class`:: The JDBC driver delegate class. ++ +Type: `java.lang.String` + +Defaults to: `org.quartz.impl.jdbcjobstore.StdJDBCDelegate` + + + +`quarkus.scheduler.store.type`:: The type of store to use. Possible values are: `ram-store`, and `database-store`. + - If set to `ram-store`, the scheduler will use the `org.quartz.simpl.RAMJobStore` job store class + - If set to `database-store`, the scheduler will use the `org.quartz.impl.jdbcjobstore.JobStoreTX` job store class. + When using this option make sure that you have the link:datasource-guide.html[agroal datasource configured] and that <> exists. ++ +Type: `io.quarkus.scheduler.runtime.SchedulerBuildTimeConfig.StoreType` + +Defaults to: `ram-store` + + + +`quarkus.scheduler.instance-id`:: The instance id of the scheduler. This is highly required when running clustered schedulers as each node in the cluster MUST have a unique instanceId. +Defaults to `AUTO` to automatically generate unique ids for each node in the cluster ++ +Type: `java.lang.String` + +Defaults to: `AUTO` + + + +`quarkus.scheduler.thread-count`:: The size of scheduler thread pool. This will initialise the number of worker threads in the pool ++ +Type: `int` + +Defaults to: `25` + + + +`quarkus.scheduler.thread-priority`:: Thread priority of worker threads in the pool. ++ +Type: `int` + +Defaults to: `5` + + +include::duration-format-note.adoc[] + +[TIP] +[[creating-scheduling-job]] +.About creating database tables when using `database-store` store type +===== +The Quarkus scheduler does not create the necessary scheduling tables in database automatically. If these tables are missing, the schuduler will throw an excpetion during application startup. +Thus you'll need to create them. To do so, copy the content from https://github.com/quarkusio/quarkus/tree/master/integration-tests/main/src/main/resources/import.sql[scheduler's sql script file] and adapt the content of the file to suit your SQL driver. +Once you are done, you can use the link:flyway-guide.html[flyway extension] to execute tables creation using the resulting SQL queries. +===== + == Package and run the application Run the application with: `./mvnw compile quarkus:dev`. diff --git a/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java b/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java index 96a28fc32d101..0165339e77ead 100644 --- a/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java +++ b/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java @@ -1,5 +1,6 @@ package io.quarkus.scheduler.deployment; +import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT; import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT; import java.text.ParseException; @@ -22,7 +23,6 @@ import org.jboss.logging.Logger; import org.quartz.CronExpression; import org.quartz.simpl.CascadingClassLoadHelper; -import org.quartz.simpl.RAMJobStore; import org.quartz.simpl.SimpleThreadPool; import io.quarkus.arc.Arc; @@ -58,10 +58,14 @@ import io.quarkus.gizmo.ResultHandle; import io.quarkus.scheduler.Scheduled; import io.quarkus.scheduler.ScheduledExecution; +import io.quarkus.scheduler.runtime.AgroalQuartzConnectionPoolingProvider; import io.quarkus.scheduler.runtime.QuartzScheduler; import io.quarkus.scheduler.runtime.ScheduledInvoker; +import io.quarkus.scheduler.runtime.SchedulerBuildTimeConfig; import io.quarkus.scheduler.runtime.SchedulerConfiguration; import io.quarkus.scheduler.runtime.SchedulerDeploymentRecorder; +import io.quarkus.scheduler.runtime.SchedulerRuntimeConfig; +import io.quarkus.scheduler.runtime.StoreType; /** * @author Martin Kouba @@ -120,7 +124,7 @@ List reflectiveClasses() { List reflectiveClasses = new ArrayList<>(); reflectiveClasses.add(new ReflectiveClassBuildItem(false, false, CascadingClassLoadHelper.class.getName())); reflectiveClasses.add(new ReflectiveClassBuildItem(true, false, SimpleThreadPool.class.getName())); - reflectiveClasses.add(new ReflectiveClassBuildItem(true, false, RAMJobStore.class.getName())); + reflectiveClasses.add(new ReflectiveClassBuildItem(true, false, AgroalQuartzConnectionPoolingProvider.class.getName())); return reflectiveClasses; } @@ -225,12 +229,38 @@ public void write(String name, byte[] data) { } @BuildStep - public void logCleanup(BuildProducer logCleanupFilter) { + @Record(RUNTIME_INIT) + public void registerConfiguration(SchedulerDeploymentRecorder recorder, + SchedulerRuntimeConfig schedulerRuntimeConfig) { + recorder.registerConfiguration(schedulerRuntimeConfig); + } + + @BuildStep + @Record(STATIC_INIT) + public void registerConfiguration(SchedulerDeploymentRecorder recorder, + SchedulerBuildTimeConfig schedulerBuildTimeConfig, + BuildProducer reflectiveClassBuildItemBuildProducer) { + + StoreType storeType = schedulerBuildTimeConfig.store.type; + reflectiveClassBuildItemBuildProducer + .produce(new ReflectiveClassBuildItem(true, false, storeType.clazz)); + + if (storeType.equals(StoreType.DATABASE_STORE)) { + reflectiveClassBuildItemBuildProducer + .produce(new ReflectiveClassBuildItem(true, false, schedulerBuildTimeConfig.store.driverDelegateClass)); + } + + recorder.registerConfiguration(schedulerBuildTimeConfig); + } + + @BuildStep + public void logCleanup(BuildProducer logCleanupFilter, + SchedulerBuildTimeConfig schedulerBuildTimeConfig) { logCleanupFilter.produce(new LogCleanupFilterBuildItem("org.quartz.impl.StdSchedulerFactory", "Quartz scheduler version:", // no need to log if it's the default "Using default implementation for", - "Quartz scheduler 'DefaultQuartzScheduler'")); + "Quartz scheduler '" + schedulerBuildTimeConfig.instanceName + "'")); logCleanupFilter.produce(new LogCleanupFilterBuildItem("org.quartz.core.QuartzScheduler", "Quartz Scheduler v", @@ -239,8 +269,8 @@ public void logCleanup(BuildProducer logCleanupFilter // no need to log if it's the default "Scheduler DefaultQuartzScheduler")); - logCleanupFilter.produce(new LogCleanupFilterBuildItem("org.quartz.simpl.RAMJobStore", - "RAMJobStore initialized.")); + StoreType storeType = schedulerBuildTimeConfig.store.type; + logCleanupFilter.produce(new LogCleanupFilterBuildItem(storeType.clazz, storeType.name + " initialized.", "Handling")); logCleanupFilter.produce(new LogCleanupFilterBuildItem("org.quartz.core.SchedulerSignalerImpl", "Initialized Scheduler Signaller of type")); diff --git a/extensions/scheduler/deployment/src/test/java/io/quarkus/scheduler/test/NoDataSourceTest.java b/extensions/scheduler/deployment/src/test/java/io/quarkus/scheduler/test/NoDataSourceTest.java new file mode 100644 index 0000000000000..1751a65f064b9 --- /dev/null +++ b/extensions/scheduler/deployment/src/test/java/io/quarkus/scheduler/test/NoDataSourceTest.java @@ -0,0 +1,31 @@ +package io.quarkus.scheduler.test; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class NoDataSourceTest { + + @RegisterExtension + static final QuarkusUnitTest test = new QuarkusUnitTest() + .setExpectedException(IllegalStateException.class) + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(SimpleJobs.class) + .addAsResource(new StringAsset("simpleJobs.cron=0/1 * * * * ?\nsimpleJobs.every=1s" + + "\nquarkus.scheduler.store.type=database-store\n"), + "application.properties")); + + @Test + public void shouldFailMissingDataSource() throws InterruptedException { + /** + * Should not reach here + */ + Assertions.fail(); + } + +} diff --git a/extensions/scheduler/runtime/pom.xml b/extensions/scheduler/runtime/pom.xml index 1b55907c431c0..0c5bd427c8154 100644 --- a/extensions/scheduler/runtime/pom.xml +++ b/extensions/scheduler/runtime/pom.xml @@ -24,6 +24,10 @@ + + io.quarkus + quarkus-core + com.oracle.substratevm svm diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/AgroalQuartzConnectionPoolingProvider.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/AgroalQuartzConnectionPoolingProvider.java new file mode 100644 index 0000000000000..b751aa8797c2c --- /dev/null +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/AgroalQuartzConnectionPoolingProvider.java @@ -0,0 +1,50 @@ +package io.quarkus.scheduler.runtime; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + +import javax.sql.DataSource; + +import org.quartz.utils.PoolingConnectionProvider; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.InstanceHandle; + +public class AgroalQuartzConnectionPoolingProvider implements PoolingConnectionProvider { + final private DataSource dataSource; + + public AgroalQuartzConnectionPoolingProvider() { + final InstanceHandle dataSourceInstanceHandle = Arc.container().instance(DataSource.class); + if (dataSourceInstanceHandle.isAvailable()) { + this.dataSource = dataSourceInstanceHandle.get(); + } else { + throw new IllegalStateException( + "JDBC Store configured but datasource is missing. You can configure your datasource by following the guide available at: https://quarkus.io/guides/datasource-guide"); + } + } + + @SuppressWarnings("unused") + public AgroalQuartzConnectionPoolingProvider(Properties properties) { + this(); + } + + @Override + public DataSource getDataSource() { + return dataSource; + } + + @Override + public Connection getConnection() throws SQLException { + return dataSource.getConnection(); + } + + @Override + public void shutdown() { + } + + @Override + public void initialize() { + + } +} diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/QuartzScheduler.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/QuartzScheduler.java index 695752483f3df..617a3f60eebca 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/QuartzScheduler.java +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/QuartzScheduler.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -113,19 +114,7 @@ void start(@Observes StartupEvent startupEvent) { if (running.compareAndSet(false, true)) { try { - // TODO: leverage quarkus config - these values are just copied from the default quartz.properties - Properties props = new Properties(); - props.put("org.quartz.scheduler.instanceName", "DefaultQuartzScheduler"); - props.put("org.quartz.scheduler.rmi.export", false); - props.put("org.quartz.scheduler.rmi.proxy", false); - props.put("org.quartz.scheduler.wrapJobExecutionInUserTransaction", false); - props.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); - props.put("org.quartz.threadPool.threadCount", "10"); - props.put("org.quartz.threadPool.threadPriority", "5"); - props.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", true); - props.put("org.quartz.threadPool.threadPriority", "5"); - props.put("org.quartz.jobStore.misfireThreshold", "60000"); - props.put("org.quartz.jobStore.class", "org.quartz.simpl.RAMJobStore"); + Properties props = getSchedulerConfigurationProperties(); SchedulerFactory schedulerFactory = new StdSchedulerFactory(props); scheduler = schedulerFactory.getScheduler(); @@ -214,6 +203,50 @@ public Job newJob(TriggerFiredBundle bundle, org.quartz.Scheduler scheduler) thr } } + private Properties getSchedulerConfigurationProperties() { + Properties props = new Properties(); + SchedulerRuntimeConfig schedulerRuntimeConfig = SchedulerConfigHolder.getSchedulerRuntimeConfig(); + SchedulerBuildTimeConfig schedulerBuildTimeConfig = SchedulerConfigHolder.getSchedulerBuildTimeConfig(); + + props.put(StdSchedulerFactory.PROP_SCHED_WRAP_JOB_IN_USER_TX, false); + props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, "org.quartz.simpl.SimpleThreadPool"); + props.put(StdSchedulerFactory.PROP_SCHED_INSTANCE_ID, schedulerRuntimeConfig.instanceId); + props.put(StdSchedulerFactory.PROP_SCHED_INSTANCE_NAME, schedulerBuildTimeConfig.instanceName); + props.put("org.quartz.threadPool.threadCount", String.valueOf(schedulerRuntimeConfig.threadCount)); + props.put("org.quartz.threadPool.threadPriority", String.valueOf(schedulerRuntimeConfig.threadPriority)); + props.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", true); + props.put("org.quartz.jobStore.misfireThreshold", + String.valueOf(schedulerBuildTimeConfig.store.misfireThreshold.toMillis())); + + switch (schedulerBuildTimeConfig.store.type) { + case RAM_STORE: + props.put(StdSchedulerFactory.PROP_JOB_STORE_CLASS, StoreType.RAM_STORE.clazz); + break; + case DATABASE_STORE: { + props.put(StdSchedulerFactory.PROP_JOB_STORE_CLASS, StoreType.DATABASE_STORE.clazz); + props.put("org.quartz.jobStore.useProperties", true); + props.put("org.quartz.jobStore.dataSource", "QUARKUS_SCHEDULER_DS"); + props.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); + props.put("org.quartz.jobStore.driverDelegateClass", schedulerBuildTimeConfig.store.driverDelegateClass); + + props.put("org.quartz.dataSource.QUARKUS_SCHEDULER_DS.connectionProvider.class", + AgroalQuartzConnectionPoolingProvider.class.getName()); + Optional clusterEnabled = schedulerBuildTimeConfig.store.clusterEnabled; + if (clusterEnabled.isPresent()) { + String interval = "20000"; // 20s + Optional clusterCheckingInterval = schedulerBuildTimeConfig.store.clusterCheckingInterval; + if (clusterCheckingInterval.isPresent()) { + interval = String.valueOf(clusterCheckingInterval.get().toMillis()); + } + props.put("org.quartz.jobStore.isClustered", clusterEnabled.get().booleanValue()); + props.put("org.quartz.jobStore.clusterCheckinInterval", interval); + } + } + } + + return props; + } + @PreDestroy void destroy() { if (running.compareAndSet(true, false)) { diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerBuildTimeConfig.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerBuildTimeConfig.java new file mode 100644 index 0000000000000..e9330605de658 --- /dev/null +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerBuildTimeConfig.java @@ -0,0 +1,88 @@ +package io.quarkus.scheduler.runtime; + +import java.time.Duration; +import java.util.Optional; + +import io.quarkus.runtime.annotations.ConfigGroup; +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; +import io.quarkus.runtime.annotations.ConvertWith; +import io.quarkus.runtime.configuration.DurationConverter; + +@ConfigRoot(name = "scheduler", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +public class SchedulerBuildTimeConfig { + /** + * The instance name of the scheduler. + */ + @ConfigItem(defaultValue = "DefaultQuartzScheduler") + public String instanceName; + + /** + * Scheduler job store configuration + */ + @ConfigItem + public SchedulerJobStoreConfig store; + + @ConfigGroup + public static class SchedulerJobStoreConfig { + + /** + * The number of duration by which a trigger must have missed its next-fire-time, in order for it to be + * considered "misfired" and thus have its misfire instruction applied. + */ + @ConfigItem(defaultValue = "1m") + @ConvertWith(DurationConverter.class) + public Duration misfireThreshold; + + /** + * The frequency at which this instance "checks-in" with the other instances of the cluster + * .This affects the rate of detecting failed instances. + * Defaults to 20 seconds. + */ + @ConfigItem + @ConvertWith(DurationConverter.class) + public Optional clusterCheckingInterval; + + /** + * Enable cluster mode or not. + * If enabled make sure to set the appropriate cluster properties. + */ + @ConfigItem + public Optional clusterEnabled; + + /** + * The JDBC driver delegate class. + * Defaults to {@link org.quartz.impl.jdbcjobstore.StdJDBCDelegate} + */ + @ConfigItem(defaultValue = "org.quartz.impl.jdbcjobstore.StdJDBCDelegate") + public String driverDelegateClass; + + /** + * The type of store to use. Possible values are: `ram-store`, `database-store`. + * Defaults to `ram-store`. + *
    + *
  • + * If set to `ram-store`, the scheduler will use the {@link org.quartz.simpl.RAMJobStore} job store class + *
  • + *
  • + * If set to `database-store`, the scheduler will use the {@link org.quartz.impl.jdbcjobstore.JobStoreTX} job store + * class. + * When using this configuration value make sure that you have the agroal datasource configured. See + * Configuring your datasource for more information. + *

    + * The Quarkus scheduler does not create the necessary scheduling tables in database automatically. + * Thus you'll need to create them before application startup. + * You can copy the content from scheduler's + * sql script file + * and adapt the file to suit your SQL driver. + *

    + *
  • + *
+ * + */ + @ConfigItem(defaultValue = "ram-store") + public StoreType type; + } +} diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerConfigHolder.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerConfigHolder.java new file mode 100644 index 0000000000000..26f313d8135ba --- /dev/null +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerConfigHolder.java @@ -0,0 +1,23 @@ +package io.quarkus.scheduler.runtime; + +class SchedulerConfigHolder { + + private static SchedulerRuntimeConfig schedulerRuntimeConfig; + private static SchedulerBuildTimeConfig schedulerBuildTimeConfig; + + public static void holdBuildtimeConfig(SchedulerBuildTimeConfig schedulerBuildTimeConfig) { + SchedulerConfigHolder.schedulerBuildTimeConfig = schedulerBuildTimeConfig; + } + + public static void holdRuntimeConfig(SchedulerRuntimeConfig schedulerRuntimeConfig) { + SchedulerConfigHolder.schedulerRuntimeConfig = schedulerRuntimeConfig; + } + + public static SchedulerRuntimeConfig getSchedulerRuntimeConfig() { + return schedulerRuntimeConfig; + } + + public static SchedulerBuildTimeConfig getSchedulerBuildTimeConfig() { + return schedulerBuildTimeConfig; + } +} diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerDeploymentRecorder.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerDeploymentRecorder.java index 959d10a881cfa..109d73776231b 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerDeploymentRecorder.java +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerDeploymentRecorder.java @@ -27,4 +27,11 @@ public void registerSchedules(List> configurations, BeanCont } } + public void registerConfiguration(SchedulerRuntimeConfig schedulerRuntimeConfig) { + SchedulerConfigHolder.holdRuntimeConfig(schedulerRuntimeConfig); + } + + public void registerConfiguration(SchedulerBuildTimeConfig schedulerBuildTimeConfig) { + SchedulerConfigHolder.holdBuildtimeConfig(schedulerBuildTimeConfig); + } } diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerRuntimeConfig.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerRuntimeConfig.java new file mode 100644 index 0000000000000..519487d33f7c7 --- /dev/null +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerRuntimeConfig.java @@ -0,0 +1,29 @@ +package io.quarkus.scheduler.runtime; + +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; + +@ConfigRoot(name = "scheduler", phase = ConfigPhase.RUN_TIME) +public class SchedulerRuntimeConfig { + /** + * The instance id of the scheduler. + * This is required when running clustered schedulers as each node in the cluster MUST have a unique {@code instanceId}. + * Defaults to `AUTO` to automatically generate unique ids for each node in the cluster + */ + @ConfigItem(defaultValue = "AUTO") + public String instanceId; + + /** + * The size of scheduler thread pool. This will initialise the number of worker threads + * in the pool + */ + @ConfigItem(defaultValue = "25") + public int threadCount; + + /** + * Thread priority of worker threads in the pool. + */ + @ConfigItem(defaultValue = "5") + public int threadPriority; +} diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/StoreType.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/StoreType.java new file mode 100644 index 0000000000000..b1119a619e6e6 --- /dev/null +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/StoreType.java @@ -0,0 +1,14 @@ +package io.quarkus.scheduler.runtime; + +public enum StoreType { + RAM_STORE("org.quartz.simpl.RAMJobStore", "RAMJobStore"), + DATABASE_STORE("org.quartz.impl.jdbcjobstore.JobStoreTX", "JobStoreTX"); + + public String name; + public String clazz; + + StoreType(String clazz, String name) { + this.clazz = clazz; + this.name = name; + } +} diff --git a/integration-tests/main/src/main/resources/META-INF/persistence.xml b/integration-tests/main/src/main/resources/META-INF/persistence.xml index 956cee5c6cbaf..580135af54446 100644 --- a/integration-tests/main/src/main/resources/META-INF/persistence.xml +++ b/integration-tests/main/src/main/resources/META-INF/persistence.xml @@ -21,6 +21,8 @@ + +