diff --git a/impl/README.md b/impl/README.md
index b65ef65c1..1c3d9dfc0 100644
--- a/impl/README.md
+++ b/impl/README.md
@@ -94,6 +94,7 @@ This SDK is modular by design—pull in only what you need:
* **serverlessworkflow-impl-function** Function support.
* **serverlessworkflow-impl-template-resolver** JaxRS URI template implementation.
* **serverlessworkflow-impl-json** Json common utilities shared by all modules in this list
+ * **serverlessworkflow-impl-cron** Cron parsing
* **serverlessworkflow-impl-http**
HTTP `Call` task handler, based on Jax-RS client
diff --git a/impl/core/pom.xml b/impl/core/pom.xml
index 1d3587aae..3ff80e8b8 100644
--- a/impl/core/pom.xml
+++ b/impl/core/pom.xml
@@ -24,10 +24,6 @@
com.github.f4b6a3
ulid-creator
-
- com.cronutils
- cron-utils
-
org.junit.jupiter
junit-jupiter-engine
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowApplication.java b/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowApplication.java
index c5da66600..b4b86e2bc 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowApplication.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowApplication.java
@@ -48,12 +48,15 @@
import io.serverlessworkflow.impl.resources.ResourceLoaderFactory;
import io.serverlessworkflow.impl.resources.URITemplateResolver;
import io.serverlessworkflow.impl.scheduler.AllStrategyCorrelationInfoFactory;
+import io.serverlessworkflow.impl.scheduler.CronResolver;
+import io.serverlessworkflow.impl.scheduler.CronResolverFactory;
import io.serverlessworkflow.impl.scheduler.DefaultWorkflowScheduler;
import io.serverlessworkflow.impl.scheduler.InMemoryAllStrategyCorrelationInfo;
import io.serverlessworkflow.impl.scheduler.WorkflowScheduler;
import io.serverlessworkflow.impl.schema.SchemaValidator;
import io.serverlessworkflow.impl.schema.SchemaValidatorFactory;
import java.net.URI;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -68,6 +71,8 @@
import java.util.ServiceLoader.Provider;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -104,6 +109,7 @@ public class WorkflowApplication implements AutoCloseable {
private final CloudEventPredicateFactory cloudEventPredicateFactory;
private final AllStrategyCorrelationInfoFactory allStrategyCorrelationInfoFactory;
private final WorkflowLifeCycleCloudEventFactory lifeCycleCloudEventFactory;
+ private final ScheduledExecutorService schedulerExecutorService;
private WorkflowApplication(Builder builder) {
this.taskFactory = builder.taskFactory;
@@ -137,6 +143,7 @@ private WorkflowApplication(Builder builder) {
this.cloudEventPredicateFactory = builder.cloudEventPredicateFactory;
this.allStrategyCorrelationInfoFactory = builder.allStrategyCorrelationInfoFactory;
this.lifeCycleCloudEventFactory = builder.lifeCycleCloudEventFactory;
+ this.schedulerExecutorService = builder.schedulerExecutorService;
}
public TaskExecutorFactory taskFactory() {
@@ -259,6 +266,8 @@ public SchemaValidator getValidator(SchemaInline inline) {
private CloudEventPredicateFactory cloudEventPredicateFactory;
private AllStrategyCorrelationInfoFactory allStrategyCorrelationInfoFactory;
private WorkflowLifeCycleCloudEventFactory lifeCycleCloudEventFactory;
+ private CronResolverFactory cronResolverFactory;
+ private ScheduledExecutorService schedulerExecutorService;
private Builder() {
ServiceLoader.load(NamedWorkflowAdditionalObject.class)
@@ -413,6 +422,11 @@ public Builder withLifeCycleCloudEventFactory(
return this;
}
+ public Builder withCronResolverFactory(CronResolverFactory cronResolverFactory) {
+ this.cronResolverFactory = cronResolverFactory;
+ return this;
+ }
+
public WorkflowApplication build() {
if (modelFactory == null) {
@@ -452,8 +466,31 @@ public WorkflowApplication build() {
if (idFactory == null) {
idFactory = new MonotonicUlidWorkflowInstanceIdFactory();
}
+
if (scheduler == null) {
- scheduler = new DefaultWorkflowScheduler();
+ if (cronResolverFactory == null) {
+ cronResolverFactory =
+ loadFirst(CronResolverFactory.class)
+ .orElseGet(
+ () ->
+ new CronResolverFactory() {
+ private CronResolver emptyResolver =
+ new CronResolver() {
+ @Override
+ public Optional nextExecution() {
+ throw new UnsupportedOperationException(
+ "Missing CronResolverFactory, please add serverlessworkflow-impl-cron dependency to your classpath");
+ }
+ };
+
+ @Override
+ public CronResolver parseCron(String cron) {
+ return emptyResolver;
+ }
+ });
+ }
+ schedulerExecutorService = Executors.newSingleThreadScheduledExecutor();
+ scheduler = new DefaultWorkflowScheduler(schedulerExecutorService, cronResolverFactory);
}
schedulerListener = new SchedulerListener(scheduler);
listeners.add(schedulerListener);
@@ -532,6 +569,9 @@ public void close() {
}
listenersByPriority.clear();
}
+ if (this.schedulerExecutorService != null) {
+ schedulerExecutorService.shutdownNow();
+ }
}
public WorkflowPositionFactory positionFactory() {
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/CronResolverFactory.java b/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/CronResolverFactory.java
index 4c67f062b..5be71bbec 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/CronResolverFactory.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/CronResolverFactory.java
@@ -15,6 +15,8 @@
*/
package io.serverlessworkflow.impl.scheduler;
-public interface CronResolverFactory {
+import io.serverlessworkflow.impl.ServicePriority;
+
+public interface CronResolverFactory extends ServicePriority {
CronResolver parseCron(String cron);
}
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/DefaultWorkflowScheduler.java b/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/DefaultWorkflowScheduler.java
index f7fcf85a0..cc0eb907e 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/DefaultWorkflowScheduler.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/DefaultWorkflowScheduler.java
@@ -17,7 +17,6 @@
import io.serverlessworkflow.impl.WorkflowDefinition;
import io.serverlessworkflow.impl.WorkflowInstance;
-import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -28,10 +27,6 @@ public class DefaultWorkflowScheduler extends ExecutorServiceWorkflowScheduler {
private final CronResolverFactory cronFactory;
- public DefaultWorkflowScheduler() {
- this(Executors.newSingleThreadScheduledExecutor(), new CronUtilsResolverFactory());
- }
-
public DefaultWorkflowScheduler(
ScheduledExecutorService service, CronResolverFactory cronFactory) {
super(service);
diff --git a/impl/cron/pom.xml b/impl/cron/pom.xml
new file mode 100644
index 000000000..53094624e
--- /dev/null
+++ b/impl/cron/pom.xml
@@ -0,0 +1,20 @@
+
+ 4.0.0
+
+ io.serverlessworkflow
+ serverlessworkflow-impl
+ 8.0.0-SNAPSHOT
+
+ serverlessworkflow-impl-cron
+ Serverless Workflow :: Impl :: Cron
+
+
+ com.cronutils
+ cron-utils
+
+
+ io.serverlessworkflow
+ serverlessworkflow-impl-core
+
+
+
\ No newline at end of file
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/CronUtilsResolver.java b/impl/cron/src/main/java/io/serverlessworkflow/impl/cron/CronUtilsResolver.java
similarity index 91%
rename from impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/CronUtilsResolver.java
rename to impl/cron/src/main/java/io/serverlessworkflow/impl/cron/CronUtilsResolver.java
index fcb7086b1..2ce36b311 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/CronUtilsResolver.java
+++ b/impl/cron/src/main/java/io/serverlessworkflow/impl/cron/CronUtilsResolver.java
@@ -13,10 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.serverlessworkflow.impl.scheduler;
+package io.serverlessworkflow.impl.cron;
import com.cronutils.model.Cron;
import com.cronutils.model.time.ExecutionTime;
+import io.serverlessworkflow.impl.scheduler.CronResolver;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Optional;
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/CronUtilsResolverFactory.java b/impl/cron/src/main/java/io/serverlessworkflow/impl/cron/CronUtilsResolverFactory.java
similarity index 83%
rename from impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/CronUtilsResolverFactory.java
rename to impl/cron/src/main/java/io/serverlessworkflow/impl/cron/CronUtilsResolverFactory.java
index 3facca0e9..c5b9f5e42 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/scheduler/CronUtilsResolverFactory.java
+++ b/impl/cron/src/main/java/io/serverlessworkflow/impl/cron/CronUtilsResolverFactory.java
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.serverlessworkflow.impl.scheduler;
+package io.serverlessworkflow.impl.cron;
import com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.parser.CronParser;
+import io.serverlessworkflow.impl.scheduler.CronResolver;
+import io.serverlessworkflow.impl.scheduler.CronResolverFactory;
-class CronUtilsResolverFactory implements CronResolverFactory {
+public class CronUtilsResolverFactory implements CronResolverFactory {
private final CronParser cronParser;
diff --git a/impl/cron/src/main/resources/META-INF/services/io.serverlessworkflow.impl.scheduler.CronResolverFactory b/impl/cron/src/main/resources/META-INF/services/io.serverlessworkflow.impl.scheduler.CronResolverFactory
new file mode 100644
index 000000000..846dc6696
--- /dev/null
+++ b/impl/cron/src/main/resources/META-INF/services/io.serverlessworkflow.impl.scheduler.CronResolverFactory
@@ -0,0 +1 @@
+io.serverlessworkflow.impl.cron.CronUtilsResolverFactory
\ No newline at end of file
diff --git a/impl/jackson/pom.xml b/impl/jackson/pom.xml
index 1a4176fdf..ec4b6d19c 100644
--- a/impl/jackson/pom.xml
+++ b/impl/jackson/pom.xml
@@ -36,5 +36,9 @@
io.serverlessworkflow
serverlessworkflow-impl-lifecycle-events
+
+ io.serverlessworkflow
+ serverlessworkflow-impl-cron
+
\ No newline at end of file
diff --git a/impl/pom.xml b/impl/pom.xml
index 8399933f5..8ff34aad6 100644
--- a/impl/pom.xml
+++ b/impl/pom.xml
@@ -130,6 +130,11 @@
serverlessworkflow-impl-a2a
${project.version}
+
+ io.serverlessworkflow
+ serverlessworkflow-impl-cron
+ ${project.version}
+
net.thisptr
jackson-jq
@@ -231,5 +236,6 @@
grpc
openapi-jackson
a2a
+ cron
diff --git a/impl/test/pom.xml b/impl/test/pom.xml
index 165ef1a98..18f12414a 100644
--- a/impl/test/pom.xml
+++ b/impl/test/pom.xml
@@ -62,6 +62,10 @@
io.serverlessworkflow
serverlessworkflow-impl-grpc
+
+ io.serverlessworkflow
+ serverlessworkflow-impl-cron
+
org.glassfish.jersey.core
jersey-client