diff --git a/cdi/shedlock-cdi-vintage/pom.xml b/cdi/shedlock-cdi-vintage/pom.xml
new file mode 100644
index 000000000..906d8a7a7
--- /dev/null
+++ b/cdi/shedlock-cdi-vintage/pom.xml
@@ -0,0 +1,91 @@
+
+
+ 4.0.0
+
+
+ shedlock-parent
+ net.javacrumbs.shedlock
+ 5.0.0-SNAPSHOT
+ ../../pom.xml
+
+
+ shedlock-cdi-vintage
+ 5.0.0-SNAPSHOT
+
+
+
+
+ net.javacrumbs.shedlock
+ shedlock-core
+ ${project.version}
+ compile
+
+
+
+ jakarta.enterprise
+ jakarta.enterprise.cdi-api
+ 2.0.2
+
+
+
+ jakarta.annotation
+ jakarta.annotation-api
+ 1.3.5
+
+
+
+ org.eclipse.microprofile.config
+ microprofile-config-api
+ 2.0.1
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.ver}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit.ver}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit.ver}
+ test
+
+
+
+ org.mockito
+ mockito-core
+ ${mockito.ver}
+ test
+
+
+ org.assertj
+ assertj-core
+ ${assertj.ver}
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+
+ net.javacrumbs.shedlock.cdivintage
+
+
+
+
+
+
+
+
diff --git a/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/SchedulerLock.java b/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/SchedulerLock.java
new file mode 100644
index 000000000..1de570832
--- /dev/null
+++ b/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/SchedulerLock.java
@@ -0,0 +1,38 @@
+package net.javacrumbs.shedlock.cdi;
+
+import javax.enterprise.util.Nonbinding;
+import javax.interceptor.InterceptorBinding;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@InterceptorBinding
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Inherited
+public @interface SchedulerLock {
+ /**
+ * Lock name.
+ */
+ @Nonbinding String name();
+
+ /**
+ * How long the lock should be kept in case the machine which obtained the lock died before releasing it.
+ * This is just a fallback, under normal circumstances the lock is released as soon the tasks finishes. Can be any format
+ * supported by Duration Conversion
+ *
+ */
+ @Nonbinding String lockAtMostFor() default "";
+
+ /**
+ * The lock will be held at least for this period of time. Can be used if you really need to execute the task
+ * at most once in given period of time. If the duration of the task is shorter than clock difference between nodes, the task can
+ * be theoretically executed more than once (one node after another). By setting this parameter, you can make sure that the
+ * lock will be kept at least for given period of time. Can be any format
+ * supported by Duration Conversion
+ */
+ @Nonbinding String lockAtLeastFor() default "";
+}
+
diff --git a/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/CdiLockConfigurationExtractor.java b/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/CdiLockConfigurationExtractor.java
new file mode 100644
index 000000000..3a5e54ab3
--- /dev/null
+++ b/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/CdiLockConfigurationExtractor.java
@@ -0,0 +1,87 @@
+/**
+ * Copyright 2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.javacrumbs.shedlock.cdi.internal;
+
+
+import net.javacrumbs.shedlock.cdi.SchedulerLock;
+import net.javacrumbs.shedlock.core.ClockProvider;
+import net.javacrumbs.shedlock.core.LockConfiguration;
+
+import java.lang.reflect.Method;
+import java.time.Duration;
+import java.util.Optional;
+
+import static java.util.Objects.requireNonNull;
+import static net.javacrumbs.shedlock.cdi.internal.Utils.parseDuration;
+
+class CdiLockConfigurationExtractor {
+ private final Duration defaultLockAtMostFor;
+ private final Duration defaultLockAtLeastFor;
+
+ CdiLockConfigurationExtractor(Duration defaultLockAtMostFor, Duration defaultLockAtLeastFor) {
+ this.defaultLockAtMostFor = requireNonNull(defaultLockAtMostFor);
+ this.defaultLockAtLeastFor = requireNonNull(defaultLockAtLeastFor);
+ }
+
+
+ Optional getLockConfiguration(Method method) {
+ Optional annotation = findAnnotation(method);
+ return annotation.map(this::getLockConfiguration);
+ }
+
+ private LockConfiguration getLockConfiguration(SchedulerLock annotation) {
+ return new LockConfiguration(
+ ClockProvider.now(),
+ getName(annotation),
+ getLockAtMostFor(annotation),
+ getLockAtLeastFor(annotation)
+ );
+ }
+
+ private String getName(SchedulerLock annotation) {
+ return annotation.name();
+ }
+
+ Duration getLockAtMostFor(SchedulerLock annotation) {
+ return getValue(
+ annotation.lockAtMostFor(),
+ this.defaultLockAtMostFor,
+ "lockAtMostFor"
+ );
+ }
+
+ Duration getLockAtLeastFor(SchedulerLock annotation) {
+ return getValue(
+ annotation.lockAtLeastFor(),
+ this.defaultLockAtLeastFor,
+ "lockAtLeastFor"
+ );
+ }
+
+ private Duration getValue(String stringValueFromAnnotation, Duration defaultValue, String paramName) {
+ if (!stringValueFromAnnotation.isEmpty()) {
+ return parseDuration(stringValueFromAnnotation);
+ } else {
+ return defaultValue;
+ }
+ }
+
+ Optional findAnnotation(Method method) {
+ return Optional.ofNullable(method.getAnnotation(SchedulerLock.class));
+ }
+}
+
+
diff --git a/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/LockingNotSupportedException.java b/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/LockingNotSupportedException.java
new file mode 100644
index 000000000..7532ee44e
--- /dev/null
+++ b/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/LockingNotSupportedException.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright 2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.javacrumbs.shedlock.cdi.internal;
+
+import net.javacrumbs.shedlock.support.LockException;
+
+class LockingNotSupportedException extends LockException {
+ LockingNotSupportedException() {
+ super("Can not lock method returning value (do not know what to return if it's locked)");
+ }
+}
diff --git a/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/SchedulerLockInterceptor.java b/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/SchedulerLockInterceptor.java
new file mode 100644
index 000000000..129fad619
--- /dev/null
+++ b/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/SchedulerLockInterceptor.java
@@ -0,0 +1,60 @@
+package net.javacrumbs.shedlock.cdi.internal;
+
+import net.javacrumbs.shedlock.cdi.SchedulerLock;
+import net.javacrumbs.shedlock.core.DefaultLockingTaskExecutor;
+import net.javacrumbs.shedlock.core.LockConfiguration;
+import net.javacrumbs.shedlock.core.LockProvider;
+import net.javacrumbs.shedlock.core.LockingTaskExecutor;
+import org.eclipse.microprofile.config.ConfigProvider;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+import java.time.Duration;
+import java.util.Objects;
+import java.util.Optional;
+
+import static net.javacrumbs.shedlock.cdi.internal.Utils.parseDuration;
+
+
+@SchedulerLock(name = "?")
+@Priority(3001)
+@Interceptor
+public class SchedulerLockInterceptor {
+ private final LockingTaskExecutor lockingTaskExecutor;
+ private final CdiLockConfigurationExtractor lockConfigurationExtractor;
+
+ @Inject
+ public SchedulerLockInterceptor(LockProvider lockProvider) {
+ this.lockingTaskExecutor = new DefaultLockingTaskExecutor(lockProvider);
+ String lockAtMostFor = getConfigValue("shedlock.defaults.lock-at-most-for");
+ String lockAtLeastFor = getConfigValue("shedlock.defaults.lock-at-least-for");
+ Objects.requireNonNull(lockAtMostFor, "shedlock.defaults.lock-at-most-for parameter is mandatory");
+ this.lockConfigurationExtractor = new CdiLockConfigurationExtractor(
+ parseDuration(lockAtMostFor),
+ lockAtLeastFor != null ? parseDuration(lockAtLeastFor) : Duration.ZERO
+ );
+ }
+
+ private static String getConfigValue(String propertyName) {
+ return ConfigProvider.getConfig().getConfigValue(propertyName).getValue();
+ }
+
+ @AroundInvoke
+ Object lock(InvocationContext context) throws Throwable {
+ Class> returnType = context.getMethod().getReturnType();
+ if (!void.class.equals(returnType) && !Void.class.equals(returnType)) {
+ throw new LockingNotSupportedException();
+ }
+
+ Optional lockConfiguration = lockConfigurationExtractor.getLockConfiguration(context.getMethod());
+ if (lockConfiguration.isPresent()) {
+ lockingTaskExecutor.executeWithLock((LockingTaskExecutor.Task) context::proceed, lockConfiguration.get());
+ return null;
+ } else {
+ return context.proceed();
+ }
+ }
+}
diff --git a/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/Utils.java b/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/Utils.java
new file mode 100644
index 000000000..3ae189000
--- /dev/null
+++ b/cdi/shedlock-cdi-vintage/src/main/java/net/javacrumbs/shedlock/cdi/internal/Utils.java
@@ -0,0 +1,19 @@
+package net.javacrumbs.shedlock.cdi.internal;
+
+import java.time.Duration;
+import java.time.format.DateTimeParseException;
+
+class Utils {
+ static Duration parseDuration(String value) {
+ value = value.trim();
+ if (value.isEmpty()) {
+ return null;
+ }
+
+ try {
+ return Duration.parse(value);
+ } catch (DateTimeParseException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/cdi/shedlock-cdi-vintage/src/main/resources/META-INF/beans.xml b/cdi/shedlock-cdi-vintage/src/main/resources/META-INF/beans.xml
new file mode 100644
index 000000000..75b9e9cce
--- /dev/null
+++ b/cdi/shedlock-cdi-vintage/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/cdi/test/quarkus-test/pom.xml b/cdi/test/quarkus-test/pom.xml
new file mode 100644
index 000000000..e7c664771
--- /dev/null
+++ b/cdi/test/quarkus-test/pom.xml
@@ -0,0 +1,125 @@
+
+
+
+ shedlock-parent
+ net.javacrumbs.shedlock
+ 5.0.0-SNAPSHOT
+ ../../../pom.xml
+
+ 4.0.0
+
+ quarkus-test
+ 5.0.0-SNAPSHOT
+
+
+ quarkus-bom
+ io.quarkus.platform
+ 2.13.3.Final
+ true
+
+
+
+
+
+ ${quarkus.platform.group-id}
+ ${quarkus.platform.artifact-id}
+ ${quarkus.platform.version}
+ pom
+ import
+
+
+
+
+
+ net.javacrumbs.shedlock
+ shedlock-cdi-vintage
+ ${project.version}
+
+
+ io.quarkus
+ quarkus-arc
+
+
+ io.quarkus
+ quarkus-scheduler
+
+
+ net.javacrumbs.shedlock
+ shedlock-provider-jdbc
+ 4.42.0
+
+
+ org.testcontainers
+ postgresql
+ 1.17.5
+
+
+ io.quarkus
+ quarkus-liquibase
+
+
+
+ io.quarkus
+ quarkus-junit5
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+ org.mockito
+ mockito-core
+ ${mockito.ver}
+ test
+
+
+ org.assertj
+ assertj-core
+ ${assertj.ver}
+ test
+
+
+
+
+
+ ${quarkus.platform.group-id}
+ quarkus-maven-plugin
+ ${quarkus.platform.version}
+ true
+
+
+
+ build
+ generate-code
+ generate-code-tests
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+ true
+
+
+
+
+
+
+ native
+
+
+ native
+
+
+
+ false
+ native
+
+
+
+
diff --git a/cdi/test/quarkus-test/src/test/java/net/javacrumbs/shedlock/quarkus/test/QuarkusConfig.java b/cdi/test/quarkus-test/src/test/java/net/javacrumbs/shedlock/quarkus/test/QuarkusConfig.java
new file mode 100644
index 000000000..a1ba035a6
--- /dev/null
+++ b/cdi/test/quarkus-test/src/test/java/net/javacrumbs/shedlock/quarkus/test/QuarkusConfig.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright 2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.javacrumbs.shedlock.quarkus.test;
+
+
+import net.javacrumbs.shedlock.cdi.SchedulerLock;
+import net.javacrumbs.shedlock.core.LockProvider;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+import javax.inject.Singleton;
+import java.io.IOException;
+
+import static net.javacrumbs.shedlock.core.LockAssert.assertLocked;
+import static org.mockito.Mockito.mock;
+
+public class QuarkusConfig {
+
+ @Produces
+ @Singleton
+ public LockProvider lockProvider() {
+ return mock(LockProvider.class);
+ }
+
+
+ @ApplicationScoped
+ static class TestBean {
+
+ public void noAnnotation() {
+ assertLocked();
+ }
+
+ @SchedulerLock(name = "normal")
+ public void normal() {
+ assertLocked();
+ }
+
+ @SchedulerLock(name = "runtimeException", lockAtMostFor = "PT0.1s")
+ public Void throwsRuntimeException() {
+ throw new RuntimeException();
+ }
+
+ @SchedulerLock(name = "exception")
+ public void throwsException() throws Exception {
+ throw new IOException();
+ }
+
+ @SchedulerLock(name = "returnsValue")
+ public int returnsValue() {
+ return 0;
+ }
+
+ @SchedulerLock(name = "${property.value}", lockAtLeastFor = "${property.lock-at-least-for}")
+ public void property() {
+
+ }
+ }
+
+
+ interface AnotherTestBean {
+ void runManually();
+ }
+
+ @ApplicationScoped
+ static class AnotherTestBeanImpl implements AnotherTestBean {
+
+ @Override
+ @SchedulerLock(name = "classAnnotation")
+ public void runManually() {
+
+ }
+ }
+}
diff --git a/cdi/test/quarkus-test/src/test/java/net/javacrumbs/shedlock/quarkus/test/QuarkusShedlockTest.java b/cdi/test/quarkus-test/src/test/java/net/javacrumbs/shedlock/quarkus/test/QuarkusShedlockTest.java
new file mode 100644
index 000000000..6f556634e
--- /dev/null
+++ b/cdi/test/quarkus-test/src/test/java/net/javacrumbs/shedlock/quarkus/test/QuarkusShedlockTest.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright 2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.javacrumbs.shedlock.quarkus.test;
+
+import io.quarkus.test.junit.QuarkusTest;
+import net.javacrumbs.shedlock.core.LockProvider;
+import net.javacrumbs.shedlock.core.SimpleLock;
+import net.javacrumbs.shedlock.quarkus.test.QuarkusConfig.AnotherTestBean;
+import net.javacrumbs.shedlock.quarkus.test.QuarkusConfig.TestBean;
+import net.javacrumbs.shedlock.support.LockException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import javax.inject.Inject;
+import java.io.IOException;
+import java.util.Optional;
+
+import static net.javacrumbs.shedlock.quarkus.test.TestUtils.hasParams;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+
+@QuarkusTest
+class QuarkusShedlockTest {
+ @Inject
+ LockProvider lockProvider;
+
+ @Inject
+ TestBean testBean;
+
+ @Inject
+ AnotherTestBean anotherTestBean;
+
+ private final SimpleLock simpleLock = mock(SimpleLock.class);
+
+ @BeforeEach
+ void prepareMocks() {
+ Mockito.reset(lockProvider, simpleLock);
+ when(lockProvider.lock(any())).thenReturn(Optional.of(simpleLock));
+ }
+
+ @Test
+ void shouldNotCallLockProviderWithNoAnnotation() {
+ assertThatThrownBy(() -> testBean.noAnnotation()).hasMessageStartingWith("The task is not locked.");
+ verifyNoInteractions(lockProvider);
+ }
+
+ @Test
+ void shouldCallLockProviderOnDirectCall() {
+ testBean.normal();
+ verify(lockProvider).lock(hasParams("normal", 30_000, 100));
+ verify(simpleLock).unlock();
+ }
+
+ @Test
+ void shouldRethrowRuntimeException() {
+ assertThatThrownBy(() -> testBean.throwsRuntimeException()).isInstanceOf(RuntimeException.class);
+ verify(lockProvider).lock(hasParams("runtimeException", 100, 100));
+ verify(simpleLock).unlock();
+ }
+
+ @Test
+ void shouldRethrowDeclaredException() {
+ assertThatThrownBy(() -> testBean.throwsException()).isInstanceOf(IOException.class);
+ verify(lockProvider).lock(hasParams("exception", 30_000, 100));
+ verify(simpleLock).unlock();
+ }
+
+ @Test
+ void shouldFailOnReturnType() {
+ assertThatThrownBy(() -> testBean.returnsValue()).isInstanceOf(LockException.class);
+ verifyNoInteractions(lockProvider);
+ }
+
+ @Test
+ @Disabled // Not implemented, waiting if anyone is going to use it. When needed, get the code from Quarkus SchedulerUtils
+ void shouldReadConfigurationProperty() {
+ testBean.property();
+ verify(lockProvider).lock(hasParams("property", 30_000, 1_000));
+ verify(simpleLock).unlock();
+ }
+
+ @Test
+ void shouldReadAnnotationFromImplementationClass() {
+ anotherTestBean.runManually();
+ verify(lockProvider).lock(hasParams("classAnnotation", 30_000, 100));
+ verify(simpleLock).unlock();
+ }
+}
diff --git a/cdi/test/quarkus-test/src/test/java/net/javacrumbs/shedlock/quarkus/test/TestUtils.java b/cdi/test/quarkus-test/src/test/java/net/javacrumbs/shedlock/quarkus/test/TestUtils.java
new file mode 100644
index 000000000..5a76b6c19
--- /dev/null
+++ b/cdi/test/quarkus-test/src/test/java/net/javacrumbs/shedlock/quarkus/test/TestUtils.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.javacrumbs.shedlock.quarkus.test;
+
+import net.javacrumbs.shedlock.core.ClockProvider;
+import net.javacrumbs.shedlock.core.LockConfiguration;
+import org.mockito.ArgumentMatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Instant;
+
+import static org.mockito.ArgumentMatchers.argThat;
+
+public class TestUtils {
+
+ private static final int GAP = 1000;
+
+ private static final Logger logger = LoggerFactory.getLogger(TestUtils.class);
+
+ public static LockConfiguration hasParams(String name, long lockAtMostFor, long lockAtLeastFor) {
+ return argThat(new ArgumentMatcher<>() {
+ @Override
+ public boolean matches(LockConfiguration c) {
+ return name.equals(c.getName())
+ && isNearTo(lockAtMostFor, c.getLockAtMostUntil())
+ && isNearTo(lockAtLeastFor, c.getLockAtLeastUntil());
+ }
+
+ @Override
+ public String toString() {
+ Instant now = ClockProvider.now();
+ return "hasParams(\"" + name + "\", " + now.plusMillis(lockAtMostFor) + ", " + now.plusMillis(lockAtLeastFor) + ")";
+ }
+ });
+ }
+
+ private static boolean isNearTo(long expected, Instant time) {
+ Instant now = ClockProvider.now();
+ Instant from = now.plusMillis(expected - GAP);
+ Instant to = now.plusMillis(expected);
+ boolean isNear = time.isAfter(from) && !time.isAfter(to);
+ if (!isNear) {
+ logger.info("Assertion failed time={} is not between {} and {}", time, from, to);
+ }
+ return isNear;
+ }
+}
diff --git a/cdi/test/quarkus-test/src/test/resources/application.properties b/cdi/test/quarkus-test/src/test/resources/application.properties
new file mode 100644
index 000000000..c583b5fbd
--- /dev/null
+++ b/cdi/test/quarkus-test/src/test/resources/application.properties
@@ -0,0 +1 @@
+shedlock.defaults.lock-at-most-for=PT30S
diff --git a/pom.xml b/pom.xml
index a2d68ee70..61ca55d13 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,6 +23,8 @@
shedlock-bom
shedlock-core
+ cdi/shedlock-cdi-vintage
+ cdi/test/quarkus-test
micronaut/shedlock-micronaut
micronaut/test/micronaut-jdbc
micronaut/test/micronaut-jdbc-template