diff --git a/pom.xml b/pom.xml
index de99f05e..49214b9c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,18 +4,10 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
-
- UTF-8
- 4.5.4
- 0.21.0
- 2.15.3
- 5.2.5
-
-
io.github.sinri
Keel
-
- 3.2.3
+ 3.2.4-SNAPSHOT
+
Keel
@@ -44,6 +36,14 @@
+
+ UTF-8
+ 4.5.4
+ 0.21.0
+ 2.15.3
+ 5.2.5
+
+
io.vertx
diff --git a/src/main/java/io/github/sinri/keel/core/KeelCronExpression.java b/src/main/java/io/github/sinri/keel/core/KeelCronExpression.java
index 4d9d86cd..a866978c 100644
--- a/src/main/java/io/github/sinri/keel/core/KeelCronExpression.java
+++ b/src/main/java/io/github/sinri/keel/core/KeelCronExpression.java
@@ -1,5 +1,7 @@
package io.github.sinri.keel.core;
+
+import javax.annotation.Nonnull;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -13,9 +15,9 @@ public class KeelCronExpression {
final Set dayOptions = new HashSet<>();
final Set monthOptions = new HashSet<>();
final Set weekdayOptions = new HashSet<>();
- private final String rawCronExpression;
+ private final @Nonnull String rawCronExpression;
- public KeelCronExpression(String rawCronExpression) {
+ public KeelCronExpression(@Nonnull String rawCronExpression) {
this.rawCronExpression = rawCronExpression;
String[] parts = rawCronExpression.trim().split("\\s+");
@@ -36,24 +38,20 @@ public KeelCronExpression(String rawCronExpression) {
parseField(weekdayExpression, weekdayOptions, 0, 6);
}
- public boolean match(Calendar currentCalendar) {
- // currentCalendar := Calendar.getInstance();
- int minute = currentCalendar.get(Calendar.MINUTE);
- int hour = currentCalendar.get(Calendar.HOUR_OF_DAY);
- int day = currentCalendar.get(Calendar.DAY_OF_MONTH);
- int month = 1 + currentCalendar.get(Calendar.MONTH);// make JAN 1, ...
- int weekday = currentCalendar.get(Calendar.DAY_OF_WEEK) - 1; // make sunday 0, ...
-
- return minuteOptions.contains(minute)
- && hourOptions.contains(hour)
- && dayOptions.contains(day)
- && monthOptions.contains(month)
- && weekdayOptions.contains(weekday);
+ public boolean match(@Nonnull Calendar currentCalendar) {
+ ParsedCalenderElements parsedCalenderElements = new ParsedCalenderElements(currentCalendar);
+ return match(parsedCalenderElements);
}
- private void parseField(String rawComponent, Set optionSet, int min, int max) {
-// System.out.println("parseField: " + rawComponent);
+ public boolean match(@Nonnull ParsedCalenderElements parsedCalenderElements) {
+ return minuteOptions.contains(parsedCalenderElements.minute)
+ && hourOptions.contains(parsedCalenderElements.hour)
+ && dayOptions.contains(parsedCalenderElements.day)
+ && monthOptions.contains(parsedCalenderElements.month)
+ && weekdayOptions.contains(parsedCalenderElements.weekday);
+ }
+ private void parseField(@Nonnull String rawComponent, @Nonnull Set optionSet, int min, int max) {
if (rawComponent.equals("*")) {
for (int i = min; i <= max; i++) {
optionSet.add(i);
@@ -106,10 +104,35 @@ private void parseField(String rawComponent, Set optionSet, int min, in
}
}
+ @Nonnull
public String getRawCronExpression() {
return rawCronExpression;
}
+ /**
+ * @since 3.2.4
+ */
+ public static class ParsedCalenderElements {
+ public final int minute;
+ public final int hour;
+ public final int day;
+ public final int month;
+ public final int weekday;
+
+ public ParsedCalenderElements(@Nonnull Calendar currentCalendar) {
+ minute = currentCalendar.get(Calendar.MINUTE);
+ hour = currentCalendar.get(Calendar.HOUR_OF_DAY);
+ day = currentCalendar.get(Calendar.DAY_OF_MONTH);
+ month = 1 + currentCalendar.get(Calendar.MONTH);// make JAN 1, ...
+ weekday = currentCalendar.get(Calendar.DAY_OF_WEEK) - 1; // make sunday 0, ...
+ }
+
+ @Override
+ public String toString() {
+ return minute + " " + hour + " " + day + " " + month + " " + weekday;
+ }
+ }
+
@Override
public String toString() {
return getRawCronExpression();
diff --git a/src/main/java/io/github/sinri/keel/facade/KeelInstance.java b/src/main/java/io/github/sinri/keel/facade/KeelInstance.java
index 6a51217e..f89314b1 100644
--- a/src/main/java/io/github/sinri/keel/facade/KeelInstance.java
+++ b/src/main/java/io/github/sinri/keel/facade/KeelInstance.java
@@ -6,7 +6,10 @@
import io.github.sinri.keel.logger.KeelLogLevel;
import io.github.sinri.keel.logger.event.KeelEventLogger;
import io.github.sinri.keel.logger.issue.center.KeelIssueRecordCenter;
-import io.vertx.core.*;
+import io.vertx.core.Future;
+import io.vertx.core.Promise;
+import io.vertx.core.Vertx;
+import io.vertx.core.VertxOptions;
import io.vertx.core.spi.cluster.ClusterManager;
import javax.annotation.Nonnull;
@@ -130,7 +133,7 @@ public KeelInstance setLogger(@Nonnull KeelEventLogger eventLogger) {
return this;
}
- public Future gracefullyClose(@Nonnull Handler> promiseHandler) {
+ public Future gracefullyClose(@Nonnull io.vertx.core.Handler> promiseHandler) {
Promise promise = Promise.promise();
promiseHandler.handle(promise);
return promise.future().compose(v -> getVertx().close());
diff --git a/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundial.java b/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundial.java
index d814e931..592fc65f 100644
--- a/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundial.java
+++ b/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundial.java
@@ -1,19 +1,22 @@
package io.github.sinri.keel.servant.sundial;
+import io.github.sinri.keel.core.KeelCronExpression;
+import io.github.sinri.keel.facade.async.KeelAsyncKit;
import io.github.sinri.keel.logger.event.KeelEventLogger;
import io.github.sinri.keel.logger.issue.center.KeelIssueRecordCenter;
import io.github.sinri.keel.verticles.KeelVerticleImplWithEventLogger;
import io.vertx.core.Future;
+import io.vertx.core.json.JsonObject;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Supplier;
import static io.github.sinri.keel.facade.KeelInstance.Keel;
/**
* @since 3.0.0
+ * @since 3.2.4 use verticle to handle the sundial plan executing.
*/
public abstract class KeelSundial extends KeelVerticleImplWithEventLogger {
private final Map planMap = new ConcurrentHashMap<>();
@@ -33,47 +36,55 @@ public void start() throws Exception {
this.timerID = Keel.getVertx().setPeriodic(delaySeconds, 60_000L, timerID -> {
Calendar calendar = Calendar.getInstance();
handleEveryMinute(calendar);
+ refreshPlans();
});
}
private void handleEveryMinute(Calendar now) {
+ KeelCronExpression.ParsedCalenderElements parsedCalenderElements = new KeelCronExpression.ParsedCalenderElements(now);
planMap.forEach((key, plan) -> {
- if (plan.cronExpression().match(now)) {
+ if (plan.cronExpression().match(parsedCalenderElements)) {
+ getLogger().debug("Sundial Plan Matched", new JsonObject()
+ .put("plan_key", plan.key())
+ .put("plan_cron", plan.cronExpression())
+ .put("now", parsedCalenderElements.toString())
+ );
plan.execute(now);
+ } else {
+ getLogger().debug("Sundial Plan Not Match", new JsonObject()
+ .put("plan_key", plan.key())
+ .put("plan_cron", plan.cronExpression())
+ .put("now", parsedCalenderElements.toString())
+ );
}
});
-
- // refresh plan, pfs {0: not-fetching, more: fetching}
- if (planFetchingSemaphore.get() == 0) {
- planFetchingSemaphore.incrementAndGet();
- fetchPlans()
- .compose(plans -> {
- if (plans == null) {
- // treat null as NOT MODIFIED
- return Future.succeededFuture();
- }
- Set toDelete = new HashSet<>(planMap.keySet());
- plans.forEach(plan -> {
- toDelete.remove(plan.key());
- planMap.put(plan.key(), plan);
- });
- if (!toDelete.isEmpty()) {
- toDelete.forEach(planMap::remove);
- }
- return Future.succeededFuture();
- })
- .eventually(() -> {
- planFetchingSemaphore.decrementAndGet();
- return Future.succeededFuture();
- });
-
- }
-
}
- @Deprecated(since = "3.0.1", forRemoval = true)
- protected Supplier> plansSupplier() {
- return null;
+ /**
+ * @since 3.2.4
+ */
+ private void refreshPlans() {
+ KeelAsyncKit.exclusivelyCall(
+ "io.github.sinri.keel.servant.sundial.KeelSundial.refreshPlans",
+ 1000L,
+ () -> {
+ return fetchPlans()
+ .compose(plans -> {
+ // treat null as NOT MODIFIED
+ if (plans != null) {
+ Set toDelete = new HashSet<>(planMap.keySet());
+ plans.forEach(plan -> {
+ toDelete.remove(plan.key());
+ planMap.put(plan.key(), plan);
+ });
+ if (!toDelete.isEmpty()) {
+ toDelete.forEach(planMap::remove);
+ }
+ }
+ return Future.succeededFuture();
+ });
+ }
+ );
}
/**
diff --git a/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundialPlan.java b/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundialPlan.java
index 50f52b51..37812b2f 100644
--- a/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundialPlan.java
+++ b/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundialPlan.java
@@ -1,16 +1,18 @@
package io.github.sinri.keel.servant.sundial;
import io.github.sinri.keel.core.KeelCronExpression;
+import io.vertx.core.Future;
import java.util.Calendar;
/**
* @since 3.0.0
+ * @since 3.2.4 change sync method `execute` to be async.
*/
public interface KeelSundialPlan {
String key();
KeelCronExpression cronExpression();
- void execute(Calendar now);
+ Future execute(Calendar now);
}
diff --git a/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundialVerticle.java b/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundialVerticle.java
new file mode 100644
index 00000000..c5129046
--- /dev/null
+++ b/src/main/java/io/github/sinri/keel/servant/sundial/KeelSundialVerticle.java
@@ -0,0 +1,31 @@
+package io.github.sinri.keel.servant.sundial;
+
+import io.github.sinri.keel.verticles.KeelVerticleImplPure;
+import io.vertx.core.Future;
+
+import javax.annotation.Nonnull;
+import java.util.Calendar;
+
+/**
+ * @since 3.2.4
+ */
+public class KeelSundialVerticle extends KeelVerticleImplPure {
+ private final KeelSundialPlan sundialPlan;
+ private final Calendar now;
+
+ public KeelSundialVerticle(@Nonnull KeelSundialPlan sundialPlan, Calendar now) {
+ this.sundialPlan = sundialPlan;
+ this.now = now;
+ }
+
+ @Override
+ public void start() throws Exception {
+ Future.succeededFuture()
+ .compose(v -> {
+ return sundialPlan.execute(now);
+ })
+ .onComplete(ar -> {
+ undeployMe();
+ });
+ }
+}