diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 32b2746d36f920..59331ea7c2f074 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -1797,6 +1797,21 @@ quarkus-undertow-spi ${project.version} + + io.quarkus + quarkus-scheduler-api + ${project.version} + + + io.quarkus + quarkus-scheduler-common + ${project.version} + + + io.quarkus + quarkus-scheduler-kotlin + ${project.version} + io.quarkus quarkus-scheduler diff --git a/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzScheduler.java b/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzScheduler.java index ec283763492e8c..d04ae8ab00a34a 100644 --- a/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzScheduler.java +++ b/extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzScheduler.java @@ -65,14 +65,14 @@ import io.quarkus.scheduler.SkippedExecution; import io.quarkus.scheduler.SuccessfulExecution; import io.quarkus.scheduler.Trigger; -import io.quarkus.scheduler.runtime.ScheduledInvoker; -import io.quarkus.scheduler.runtime.ScheduledMethodMetadata; -import io.quarkus.scheduler.runtime.SchedulerContext; +import io.quarkus.scheduler.common.runtime.ScheduledInvoker; +import io.quarkus.scheduler.common.runtime.ScheduledMethodMetadata; +import io.quarkus.scheduler.common.runtime.SchedulerContext; +import io.quarkus.scheduler.common.runtime.SkipConcurrentExecutionInvoker; +import io.quarkus.scheduler.common.runtime.SkipPredicateInvoker; +import io.quarkus.scheduler.common.runtime.StatusEmitterInvoker; +import io.quarkus.scheduler.common.runtime.util.SchedulerUtils; import io.quarkus.scheduler.runtime.SchedulerRuntimeConfig; -import io.quarkus.scheduler.runtime.SkipConcurrentExecutionInvoker; -import io.quarkus.scheduler.runtime.SkipPredicateInvoker; -import io.quarkus.scheduler.runtime.StatusEmitterInvoker; -import io.quarkus.scheduler.runtime.util.SchedulerUtils; import io.smallrye.common.vertx.VertxContext; import io.vertx.core.Handler; import io.vertx.core.Vertx; diff --git a/extensions/scheduler/api/pom.xml b/extensions/scheduler/api/pom.xml new file mode 100644 index 00000000000000..19a081ddd5585b --- /dev/null +++ b/extensions/scheduler/api/pom.xml @@ -0,0 +1,25 @@ + + + + io.quarkus + quarkus-scheduler-parent + 999-SNAPSHOT + + 4.0.0 + + quarkus-scheduler-api + Quarkus - Scheduler - API + + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-vertx + + + diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/FailedExecution.java b/extensions/scheduler/api/src/main/java/io/quarkus/scheduler/FailedExecution.java similarity index 100% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/FailedExecution.java rename to extensions/scheduler/api/src/main/java/io/quarkus/scheduler/FailedExecution.java diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/Scheduled.java b/extensions/scheduler/api/src/main/java/io/quarkus/scheduler/Scheduled.java similarity index 100% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/Scheduled.java rename to extensions/scheduler/api/src/main/java/io/quarkus/scheduler/Scheduled.java diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/ScheduledExecution.java b/extensions/scheduler/api/src/main/java/io/quarkus/scheduler/ScheduledExecution.java similarity index 100% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/ScheduledExecution.java rename to extensions/scheduler/api/src/main/java/io/quarkus/scheduler/ScheduledExecution.java diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/Scheduler.java b/extensions/scheduler/api/src/main/java/io/quarkus/scheduler/Scheduler.java similarity index 100% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/Scheduler.java rename to extensions/scheduler/api/src/main/java/io/quarkus/scheduler/Scheduler.java diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/SkippedExecution.java b/extensions/scheduler/api/src/main/java/io/quarkus/scheduler/SkippedExecution.java similarity index 100% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/SkippedExecution.java rename to extensions/scheduler/api/src/main/java/io/quarkus/scheduler/SkippedExecution.java diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/SuccessfulExecution.java b/extensions/scheduler/api/src/main/java/io/quarkus/scheduler/SuccessfulExecution.java similarity index 100% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/SuccessfulExecution.java rename to extensions/scheduler/api/src/main/java/io/quarkus/scheduler/SuccessfulExecution.java diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/Trigger.java b/extensions/scheduler/api/src/main/java/io/quarkus/scheduler/Trigger.java similarity index 100% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/Trigger.java rename to extensions/scheduler/api/src/main/java/io/quarkus/scheduler/Trigger.java diff --git a/extensions/scheduler/common/pom.xml b/extensions/scheduler/common/pom.xml new file mode 100644 index 00000000000000..2755b076bb052a --- /dev/null +++ b/extensions/scheduler/common/pom.xml @@ -0,0 +1,41 @@ + + + + io.quarkus + quarkus-scheduler-parent + 999-SNAPSHOT + + 4.0.0 + + quarkus-scheduler-common + Quarkus - Scheduler - Common + + + + io.quarkus + quarkus-scheduler-api + + + com.cronutils + cron-utils + + + org.slf4j + slf4j-simple + + + org.glassfish + javax.el + + + + + + org.junit.jupiter + junit-jupiter + test + + + diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/DefaultInvoker.java b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/DefaultInvoker.java similarity index 94% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/DefaultInvoker.java rename to extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/DefaultInvoker.java index 06d07e7e460eab..63ec3717646b8a 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/DefaultInvoker.java +++ b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/DefaultInvoker.java @@ -1,4 +1,4 @@ -package io.quarkus.scheduler.runtime; +package io.quarkus.scheduler.common.runtime; import java.util.concurrent.CompletionStage; diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/DelegateInvoker.java b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/DelegateInvoker.java similarity index 87% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/DelegateInvoker.java rename to extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/DelegateInvoker.java index 725b92147d7492..36ca1d9c66fbdc 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/DelegateInvoker.java +++ b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/DelegateInvoker.java @@ -1,4 +1,4 @@ -package io.quarkus.scheduler.runtime; +package io.quarkus.scheduler.common.runtime; abstract class DelegateInvoker implements ScheduledInvoker { diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/ScheduledInvoker.java b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/ScheduledInvoker.java similarity index 93% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/ScheduledInvoker.java rename to extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/ScheduledInvoker.java index 1e775de35d784a..16e9cee3d5e71f 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/ScheduledInvoker.java +++ b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/ScheduledInvoker.java @@ -1,4 +1,4 @@ -package io.quarkus.scheduler.runtime; +package io.quarkus.scheduler.common.runtime; import java.util.concurrent.CompletionStage; diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/ScheduledMethodMetadata.java b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/ScheduledMethodMetadata.java similarity index 95% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/ScheduledMethodMetadata.java rename to extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/ScheduledMethodMetadata.java index 565f2fb9664d14..9b90bea8102ed4 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/ScheduledMethodMetadata.java +++ b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/ScheduledMethodMetadata.java @@ -1,4 +1,4 @@ -package io.quarkus.scheduler.runtime; +package io.quarkus.scheduler.common.runtime; import java.util.List; @@ -47,4 +47,4 @@ public void setSchedules(List schedules) { this.schedules = schedules; } -} \ No newline at end of file +} diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerContext.java b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/SchedulerContext.java similarity index 95% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerContext.java rename to extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/SchedulerContext.java index 24e67eafc1d672..0c7f8cab98c4d7 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerContext.java +++ b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/SchedulerContext.java @@ -1,4 +1,4 @@ -package io.quarkus.scheduler.runtime; +package io.quarkus.scheduler.common.runtime; import java.lang.reflect.InvocationTargetException; import java.util.List; diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipConcurrentExecutionInvoker.java b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/SkipConcurrentExecutionInvoker.java similarity index 97% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipConcurrentExecutionInvoker.java rename to extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/SkipConcurrentExecutionInvoker.java index 06bc8a80aeba23..1d687a8ad1e61d 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipConcurrentExecutionInvoker.java +++ b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/SkipConcurrentExecutionInvoker.java @@ -1,4 +1,4 @@ -package io.quarkus.scheduler.runtime; +package io.quarkus.scheduler.common.runtime; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipPredicateInvoker.java b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/SkipPredicateInvoker.java similarity index 97% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipPredicateInvoker.java rename to extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/SkipPredicateInvoker.java index c20478b5f7c949..344b36e65394b5 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SkipPredicateInvoker.java +++ b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/SkipPredicateInvoker.java @@ -1,4 +1,4 @@ -package io.quarkus.scheduler.runtime; +package io.quarkus.scheduler.common.runtime; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/StatusEmitterInvoker.java b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/StatusEmitterInvoker.java similarity index 97% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/StatusEmitterInvoker.java rename to extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/StatusEmitterInvoker.java index 50367f5d5cdcc6..46d3eaccf4b59e 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/StatusEmitterInvoker.java +++ b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/StatusEmitterInvoker.java @@ -1,4 +1,4 @@ -package io.quarkus.scheduler.runtime; +package io.quarkus.scheduler.common.runtime; import java.util.concurrent.CompletionStage; diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/util/SchedulerUtils.java b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/util/SchedulerUtils.java similarity index 99% rename from extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/util/SchedulerUtils.java rename to extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/util/SchedulerUtils.java index 3fc871b911f1d3..dbc103f12c0a78 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/util/SchedulerUtils.java +++ b/extensions/scheduler/common/src/main/java/io/quarkus/scheduler/common/runtime/util/SchedulerUtils.java @@ -1,4 +1,4 @@ -package io.quarkus.scheduler.runtime.util; +package io.quarkus.scheduler.common.runtime.util; import static io.smallrye.common.expression.Expression.Flag.LENIENT_SYNTAX; import static io.smallrye.common.expression.Expression.Flag.NO_TRIM; diff --git a/extensions/scheduler/runtime/src/test/java/io/quarkus/scheduler/runtime/util/SchedulerUtilsTest.java b/extensions/scheduler/common/src/test/java/io/quarkus/scheduler/runtime/util/SchedulerUtilsTest.java similarity index 96% rename from extensions/scheduler/runtime/src/test/java/io/quarkus/scheduler/runtime/util/SchedulerUtilsTest.java rename to extensions/scheduler/common/src/test/java/io/quarkus/scheduler/runtime/util/SchedulerUtilsTest.java index 5d1b8b2aef6c91..a6d9d2fcbcfe72 100644 --- a/extensions/scheduler/runtime/src/test/java/io/quarkus/scheduler/runtime/util/SchedulerUtilsTest.java +++ b/extensions/scheduler/common/src/test/java/io/quarkus/scheduler/runtime/util/SchedulerUtilsTest.java @@ -3,6 +3,8 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import io.quarkus.scheduler.common.runtime.util.SchedulerUtils; + public class SchedulerUtilsTest { @Test diff --git a/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/KotlinUtil.java b/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/KotlinUtil.java new file mode 100644 index 00000000000000..8b57af2c6df2df --- /dev/null +++ b/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/KotlinUtil.java @@ -0,0 +1,38 @@ +package io.quarkus.scheduler.deployment; + +import org.jboss.jandex.MethodInfo; +import org.jboss.jandex.Type; + +final class KotlinUtil { + + private static final Type VOID_CLASS = Type.create(SchedulerDotNames.VOID, Type.Kind.CLASS); + + private KotlinUtil() { + } + + static boolean isSuspendMethod(MethodInfo methodInfo) { + if (!methodInfo.parameters().isEmpty()) { + return methodInfo.parameters().get(methodInfo.parameters().size() - 1).name() + .equals(SchedulerDotNames.CONTINUATION); + } + return false; + } + + static Type determineReturnTypeOfSuspendMethod(MethodInfo methodInfo) { + Type lastParamType = methodInfo.parameters().get(methodInfo.parameters().size() - 1); + if (lastParamType.kind() != Type.Kind.PARAMETERIZED_TYPE) { + throw new IllegalStateException("Something went wrong during parameter type resolution - expected " + + lastParamType + " to be a Continuation with a generic type"); + } + lastParamType = lastParamType.asParameterizedType().arguments().get(0); + if (lastParamType.kind() != Type.Kind.WILDCARD_TYPE) { + throw new IllegalStateException("Something went wrong during parameter type resolution - expected " + + lastParamType + " to be a Continuation with a generic type"); + } + lastParamType = lastParamType.asWildcardType().superBound(); + if (lastParamType.name().equals(SchedulerDotNames.KOTLIN_UNIT)) { + return VOID_CLASS; + } + return lastParamType; + } +} diff --git a/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/ScheduledBusinessMethodItem.java b/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/ScheduledBusinessMethodItem.java index 2a5b0d77bdf87f..acce3bce521f43 100644 --- a/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/ScheduledBusinessMethodItem.java +++ b/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/ScheduledBusinessMethodItem.java @@ -25,7 +25,7 @@ public ScheduledBusinessMethodItem(BeanInfo bean, MethodInfo method, List params = method.parameters(); - if (params.size() > 1 - || (params.size() == 1 && !params.get(0).equals(SCHEDULED_EXECUTION_TYPE))) { + int maxParamSize = isSuspendMethod ? 2 : 1; + if (params.size() > maxParamSize + || (params.size() == maxParamSize && !params.get(0).equals(SCHEDULED_EXECUTION_TYPE))) { errors.add(new IllegalStateException(String.format( "Invalid scheduled business method parameters %s [method: %s, bean: %s]", params, method, scheduledMethod.getBean()))); } - if (!isValidReturnType(method.returnType())) { - errors.add(new IllegalStateException( - String.format( - "Scheduled business method must return void, CompletionStage or Uni [method: %s, bean: %s]", - method, scheduledMethod.getBean()))); + if (!isValidReturnType(method)) { + if (isSuspendMethod) { + errors.add(new IllegalStateException( + String.format( + "Suspending scheduled business method must return Unit [method: %s, bean: %s]", + method, scheduledMethod.getBean()))); + } else { + errors.add(new IllegalStateException( + String.format( + "Scheduled business method must return void, CompletionStage or Uni [method: %s, bean: %s]", + method, scheduledMethod.getBean()))); + } } // Validate cron() and every() expressions CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(config.cronType)); @@ -233,7 +244,8 @@ void validateScheduledBusinessMethods(SchedulerConfig config, List buildItemBuildProducer) { + try { + Thread.currentThread().getContextClassLoader().loadClass("kotlinx.coroutines.CoroutineScope"); + buildItemBuildProducer.produce(AdditionalBeanBuildItem.builder() + .addBeanClass("io.quarkus.scheduler.kotlin.runtime.ApplicationCoroutineScope") + .setUnremovable().build()); + } catch (ClassNotFoundException e) { + // ignore + } + + } + } diff --git a/extensions/scheduler/kotlin/pom.xml b/extensions/scheduler/kotlin/pom.xml new file mode 100644 index 00000000000000..f7f36ea3270c06 --- /dev/null +++ b/extensions/scheduler/kotlin/pom.xml @@ -0,0 +1,114 @@ + + + + io.quarkus + quarkus-scheduler-parent + 999-SNAPSHOT + + 4.0.0 + + quarkus-scheduler-kotlin + Quarkus - Scheduler - Kotlin + + + + io.quarkus + quarkus-scheduler-common + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-vertx + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + true + + + org.jetbrains.kotlinx + kotlinx-coroutines-jdk8 + true + + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + + compile + + + + test-compile + + test-compile + + + + + ${maven.compiler.target} + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + default-compile + none + + + + default-testCompile + none + + + java-compile + compile + + compile + + + + java-test-compile + test-compile + + testCompile + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + false + + + + + diff --git a/extensions/scheduler/kotlin/src/main/kotlin/io/quarkus/scheduler/kotlin/runtime/AbstractCoroutineInvoker.kt b/extensions/scheduler/kotlin/src/main/kotlin/io/quarkus/scheduler/kotlin/runtime/AbstractCoroutineInvoker.kt new file mode 100644 index 00000000000000..1ed8030e51c666 --- /dev/null +++ b/extensions/scheduler/kotlin/src/main/kotlin/io/quarkus/scheduler/kotlin/runtime/AbstractCoroutineInvoker.kt @@ -0,0 +1,25 @@ +package io.quarkus.scheduler.kotlin.runtime + +import io.quarkus.arc.Arc +import io.quarkus.scheduler.ScheduledExecution +import io.quarkus.scheduler.common.runtime.ScheduledInvoker +import io.vertx.core.Vertx +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.async +import kotlinx.coroutines.future.asCompletableFuture +import java.util.concurrent.CompletionStage + +abstract class AbstractCoroutineInvoker: ScheduledInvoker { + + override fun invoke(execution: ScheduledExecution): CompletionStage { + val coroutineScope = Arc.container().instance(ApplicationCoroutineScope::class.java).get() + val dispatcher: CoroutineDispatcher = Vertx.currentContext()?.let(::VertxDispatcher) + ?: throw IllegalStateException("No Vertx context found") + + return coroutineScope.async(context = dispatcher) { + invokeBean(execution) + }.asCompletableFuture() + } + + abstract suspend fun invokeBean(execution: ScheduledExecution): Void +} diff --git a/extensions/scheduler/kotlin/src/main/kotlin/io/quarkus/scheduler/kotlin/runtime/ApplicationCoroutineScope.kt b/extensions/scheduler/kotlin/src/main/kotlin/io/quarkus/scheduler/kotlin/runtime/ApplicationCoroutineScope.kt new file mode 100644 index 00000000000000..dc38c5c7369948 --- /dev/null +++ b/extensions/scheduler/kotlin/src/main/kotlin/io/quarkus/scheduler/kotlin/runtime/ApplicationCoroutineScope.kt @@ -0,0 +1,19 @@ +package io.quarkus.scheduler.kotlin.runtime + +import io.quarkus.arc.Unremovable +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import javax.annotation.PreDestroy +import javax.inject.Singleton +import kotlin.coroutines.CoroutineContext + +@Singleton +class ApplicationCoroutineScope : CoroutineScope, AutoCloseable { + override val coroutineContext: CoroutineContext = SupervisorJob() + + @PreDestroy + override fun close() { + coroutineContext.cancel() + } +} diff --git a/extensions/scheduler/kotlin/src/main/kotlin/io/quarkus/scheduler/kotlin/runtime/VertxDispatcher.kt b/extensions/scheduler/kotlin/src/main/kotlin/io/quarkus/scheduler/kotlin/runtime/VertxDispatcher.kt new file mode 100644 index 00000000000000..dfa1008a94dd79 --- /dev/null +++ b/extensions/scheduler/kotlin/src/main/kotlin/io/quarkus/scheduler/kotlin/runtime/VertxDispatcher.kt @@ -0,0 +1,24 @@ +package io.quarkus.scheduler.kotlin.runtime + +import io.quarkus.arc.Arc +import io.vertx.core.Context +import kotlinx.coroutines.CoroutineDispatcher +import kotlin.coroutines.CoroutineContext + +class VertxDispatcher(private val vertxContext: Context) : CoroutineDispatcher() { + override fun dispatch(context: CoroutineContext, block: Runnable) { + val requestContext = Arc.container().requestContext() + vertxContext.runOnContext { + if (requestContext.isActive) { + block.run() + } else { + try { + requestContext.activate() + block.run() + } finally { + requestContext.terminate() + } + } + } + } +} diff --git a/extensions/scheduler/pom.xml b/extensions/scheduler/pom.xml index 8b620bde336771..a763e4e95e6d8b 100644 --- a/extensions/scheduler/pom.xml +++ b/extensions/scheduler/pom.xml @@ -16,6 +16,9 @@ deployment + api + common + kotlin runtime diff --git a/extensions/scheduler/runtime/pom.xml b/extensions/scheduler/runtime/pom.xml index 32d063c8b7c8ed..4c4ddf5031ece8 100644 --- a/extensions/scheduler/runtime/pom.xml +++ b/extensions/scheduler/runtime/pom.xml @@ -15,25 +15,15 @@ io.quarkus - quarkus-arc + quarkus-scheduler-kotlin io.quarkus - quarkus-vertx + quarkus-arc - com.cronutils - cron-utils - - - org.slf4j - slf4j-simple - - - org.glassfish - javax.el - - + io.quarkus + quarkus-vertx org.jboss.slf4j @@ -49,12 +39,6 @@ quarkus-vertx-http true - - - org.junit.jupiter - junit-jupiter - test - diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerRecorder.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerRecorder.java index 5c5a808336d696..76f68553b4110b 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerRecorder.java +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SchedulerRecorder.java @@ -7,6 +7,8 @@ import com.cronutils.model.CronType; import io.quarkus.runtime.annotations.Recorder; +import io.quarkus.scheduler.common.runtime.ScheduledMethodMetadata; +import io.quarkus.scheduler.common.runtime.SchedulerContext; @Recorder public class SchedulerRecorder { diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SimpleScheduler.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SimpleScheduler.java index c2ea0c5b36bc2d..ae6e282a0e301e 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SimpleScheduler.java +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/SimpleScheduler.java @@ -44,7 +44,13 @@ import io.quarkus.scheduler.SkippedExecution; import io.quarkus.scheduler.SuccessfulExecution; import io.quarkus.scheduler.Trigger; -import io.quarkus.scheduler.runtime.util.SchedulerUtils; +import io.quarkus.scheduler.common.runtime.ScheduledInvoker; +import io.quarkus.scheduler.common.runtime.ScheduledMethodMetadata; +import io.quarkus.scheduler.common.runtime.SchedulerContext; +import io.quarkus.scheduler.common.runtime.SkipConcurrentExecutionInvoker; +import io.quarkus.scheduler.common.runtime.SkipPredicateInvoker; +import io.quarkus.scheduler.common.runtime.StatusEmitterInvoker; +import io.quarkus.scheduler.common.runtime.util.SchedulerUtils; import io.smallrye.common.vertx.VertxContext; import io.vertx.core.Context; import io.vertx.core.Handler; diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/devconsole/SchedulerDevConsoleRecorder.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/devconsole/SchedulerDevConsoleRecorder.java index f5b8de54a70c9e..2f98d3737d4de7 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/devconsole/SchedulerDevConsoleRecorder.java +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/runtime/devconsole/SchedulerDevConsoleRecorder.java @@ -13,10 +13,10 @@ import io.quarkus.scheduler.ScheduledExecution; import io.quarkus.scheduler.Scheduler; import io.quarkus.scheduler.Trigger; -import io.quarkus.scheduler.runtime.ScheduledInvoker; -import io.quarkus.scheduler.runtime.ScheduledMethodMetadata; -import io.quarkus.scheduler.runtime.SchedulerContext; -import io.quarkus.scheduler.runtime.util.SchedulerUtils; +import io.quarkus.scheduler.common.runtime.ScheduledInvoker; +import io.quarkus.scheduler.common.runtime.ScheduledMethodMetadata; +import io.quarkus.scheduler.common.runtime.SchedulerContext; +import io.quarkus.scheduler.common.runtime.util.SchedulerUtils; import io.smallrye.common.vertx.VertxContext; import io.vertx.core.Handler; import io.vertx.core.MultiMap; diff --git a/extensions/spring-scheduled/deployment/src/main/java/io/quarkus/spring/scheduled/deployment/SpringScheduledProcessor.java b/extensions/spring-scheduled/deployment/src/main/java/io/quarkus/spring/scheduled/deployment/SpringScheduledProcessor.java index b749cf184a6bfe..1871fc89ca1f05 100644 --- a/extensions/spring-scheduled/deployment/src/main/java/io/quarkus/spring/scheduled/deployment/SpringScheduledProcessor.java +++ b/extensions/spring-scheduled/deployment/src/main/java/io/quarkus/spring/scheduled/deployment/SpringScheduledProcessor.java @@ -24,8 +24,8 @@ import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.scheduler.common.runtime.util.SchedulerUtils; import io.quarkus.scheduler.deployment.ScheduledBusinessMethodItem; -import io.quarkus.scheduler.runtime.util.SchedulerUtils; /** * A simple processor that search for Spring Scheduled annotations in Beans and produce diff --git a/integration-tests/resteasy-reactive-kotlin/standard/pom.xml b/integration-tests/resteasy-reactive-kotlin/standard/pom.xml index 1e444780fe8e35..0c3157eb28d088 100644 --- a/integration-tests/resteasy-reactive-kotlin/standard/pom.xml +++ b/integration-tests/resteasy-reactive-kotlin/standard/pom.xml @@ -31,6 +31,10 @@ io.quarkus quarkus-smallrye-fault-tolerance + + io.quarkus + quarkus-scheduler + io.quarkus quarkus-kotlin @@ -147,6 +151,19 @@ + + io.quarkus + quarkus-scheduler-deployment + ${project.version} + pom + test + + + * + * + + + diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ScheduledEndpoint.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ScheduledEndpoint.kt new file mode 100644 index 00000000000000..2109028b7e9cd3 --- /dev/null +++ b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ScheduledEndpoint.kt @@ -0,0 +1,36 @@ +package io.quarkus.it.resteasy.reactive.kotlin + +import io.quarkus.scheduler.Scheduled +import io.quarkus.scheduler.ScheduledExecution +import kotlinx.coroutines.delay +import java.util.concurrent.atomic.AtomicInteger +import javax.ws.rs.GET +import javax.ws.rs.Path +import javax.ws.rs.core.Response + +@Path("scheduled") +class ScheduledEndpoint { + + private val num1 = AtomicInteger(0) + private val num2 = AtomicInteger(0) + + @Scheduled(every = "0.5s") + suspend fun scheduled1() { + delay(100) + num1.compareAndSet(0, 1) + } + + @Scheduled(every = "0.5s") + suspend fun scheduled2(scheduledExecution: ScheduledExecution) { + delay(100) + num2.compareAndSet(0, 1) + } + + @Path("num1") + @GET + fun num1() = Response.status(200 + num1.get()).build() + + @Path("num2") + @GET + fun num2() = Response.status(200 + num2.get()).build() +} diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ScheduledEndpointTest.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ScheduledEndpointTest.kt new file mode 100644 index 00000000000000..5d2a3c8ac25585 --- /dev/null +++ b/integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ScheduledEndpointTest.kt @@ -0,0 +1,28 @@ +package io.quarkus.it.resteasy.reactive.kotlin + +import io.quarkus.test.junit.QuarkusTest +import io.restassured.module.kotlin.extensions.Then +import io.restassured.module.kotlin.extensions.When +import org.junit.jupiter.api.Test + +@QuarkusTest +class ScheduledEndpointTest { + + @Test + fun testScheduledMethodWithNoArg() { + When { + get("/scheduled/num1") + } Then { + statusCode(201) + } + } + + @Test + fun testScheduledMethodWithScheduledExecution() { + When { + get("/scheduled/num2") + } Then { + statusCode(201) + } + } +}