Skip to content

Commit

Permalink
feat(#93): refactor TriggerEvaluator interface API
Browse files Browse the repository at this point in the history
  • Loading branch information
zero88 committed Dec 20, 2023
1 parent b25edcd commit 36bc21d
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public abstract class AbstractSchedulerBuilder<IN, OUT, T extends Trigger, S ext

@Override
public @NotNull TriggerEvaluator triggerEvaluator() {
return Optional.ofNullable(evaluator).orElseGet(DefaultTriggerEvaluator::noop);
return Optional.ofNullable(evaluator).orElseGet(DefaultTriggerEvaluator::new);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package io.github.zero88.schedulerx.impl;

import java.util.Optional;

import org.jetbrains.annotations.ApiStatus.Internal;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import io.github.zero88.schedulerx.trigger.AfterTriggerEvaluator;
import io.github.zero88.schedulerx.trigger.BeforeTriggerEvaluator;
import io.github.zero88.schedulerx.trigger.Trigger;
import io.github.zero88.schedulerx.trigger.TriggerContext;
import io.github.zero88.schedulerx.trigger.TriggerEvaluator;
Expand All @@ -12,11 +16,20 @@
@Internal
public class DefaultTriggerEvaluator implements TriggerEvaluator {

static TriggerEvaluator noop() {
return new DefaultTriggerEvaluator();
private BeforeTriggerEvaluator before = (trigger, ctx, externalId) -> Future.succeededFuture(ctx);
private AfterTriggerEvaluator after = (trigger, ctx, externalId, round) -> Future.succeededFuture(ctx);
private TriggerEvaluator next;

public DefaultTriggerEvaluator() { }

DefaultTriggerEvaluator(BeforeTriggerEvaluator beforeEvaluator, AfterTriggerEvaluator afterEvaluator) {
before = Optional.ofNullable(beforeEvaluator).orElse(before);
after = Optional.ofNullable(afterEvaluator).orElse(after);
}

private TriggerEvaluator next;
public static TriggerEvaluator init(BeforeTriggerEvaluator beforeEvaluator, AfterTriggerEvaluator afterEvaluator) {
return new DefaultTriggerEvaluator(beforeEvaluator, afterEvaluator);
}

@Override
public final @NotNull Future<TriggerContext> beforeTrigger(@NotNull Trigger trigger,
Expand Down Expand Up @@ -45,13 +58,13 @@ static TriggerEvaluator noop() {
protected Future<TriggerContext> internalBeforeTrigger(@NotNull Trigger trigger,
@NotNull TriggerContext triggerContext,
@Nullable Object externalId) {
return Future.succeededFuture(triggerContext);
return before.beforeTrigger(trigger, triggerContext, externalId);
}

protected Future<TriggerContext> internalAfterTrigger(@NotNull Trigger trigger,
@NotNull TriggerContext triggerContext,
@Nullable Object externalId, long round) {
return Future.succeededFuture(triggerContext);
return after.afterTrigger(trigger, triggerContext, externalId, round);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.github.zero88.schedulerx.trigger;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import io.vertx.core.Future;

/**
* Represents for the trigger context checker on after trigger
*
* @since 2.0.0
*/
@FunctionalInterface
public interface AfterTriggerEvaluator {

/**
* Verify if the trigger should stop executing immediately after one round of execution begins.
*
* @param trigger the trigger
* @param triggerContext the trigger context
* @param externalId the job external id
* @param round the current execution round
* @since 2.0.0
*/
@NotNull Future<TriggerContext> afterTrigger(@NotNull Trigger trigger, @NotNull TriggerContext triggerContext,
@Nullable Object externalId, long round);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.github.zero88.schedulerx.trigger;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import io.vertx.core.Future;

/**
* Represents for the trigger context checker on before trigger
*
* @since 2.0.0
*/
@FunctionalInterface
public interface BeforeTriggerEvaluator {

/**
* Verify if the trigger can run before each execution round is started.
*
* @param trigger the trigger
* @param triggerContext the trigger context
* @param externalId the job external id
* @return a future of the trigger context that is evaluated
*/
@NotNull Future<TriggerContext> beforeTrigger(@NotNull Trigger trigger, @NotNull TriggerContext triggerContext,
@Nullable Object externalId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
import java.time.Instant;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import io.github.zero88.schedulerx.Job;
import io.github.zero88.schedulerx.JobData;
import io.github.zero88.schedulerx.SchedulingMonitor;
import io.github.zero88.schedulerx.TimeoutPolicy;
import io.github.zero88.schedulerx.impl.AbstractScheduler;
import io.github.zero88.schedulerx.impl.AbstractSchedulerBuilder;
import io.github.zero88.schedulerx.impl.DefaultTriggerEvaluator;
import io.github.zero88.schedulerx.impl.TriggerContextFactory;
import io.github.zero88.schedulerx.trigger.TriggerCondition.ReasonCode;
import io.vertx.core.Future;
Expand All @@ -27,7 +25,7 @@ final class IntervalSchedulerImpl<IN, OUT> extends AbstractScheduler<IN, OUT, In
IntervalSchedulerImpl(@NotNull Job<IN, OUT> job, @NotNull JobData<IN> jobData, @NotNull TimeoutPolicy timeoutPolicy,
@NotNull SchedulingMonitor<OUT> monitor, @NotNull IntervalTrigger trigger,
@NotNull TriggerEvaluator evaluator, @NotNull Vertx vertx) {
super(job, jobData, timeoutPolicy, monitor, trigger, new IntervalTriggerEvaluator().andThen(evaluator), vertx);
super(job, jobData, timeoutPolicy, monitor, trigger, createTriggerEvaluator().andThen(evaluator), vertx);
}

protected @NotNull Future<Long> registerTimer(WorkerExecutor workerExecutor) {
Expand Down Expand Up @@ -70,20 +68,14 @@ static final class IntervalSchedulerBuilderImpl<IN, OUT>

}


static final class IntervalTriggerEvaluator extends DefaultTriggerEvaluator {

@Override
protected Future<TriggerContext> internalAfterTrigger(@NotNull Trigger trigger,
@NotNull TriggerContext triggerContext,
@Nullable Object externalId, long round) {
static TriggerEvaluator createTriggerEvaluator() {
return TriggerEvaluator.byAfter((trigger, triggerContext, externalId, round) -> {
IntervalTrigger interval = (IntervalTrigger) trigger;
if (interval.noRepeatIndefinitely() && round >= interval.getRepeat()) {
return Future.succeededFuture(TriggerContextFactory.stop(triggerContext, ReasonCode.STOP_BY_CONFIG));
}
return Future.succeededFuture(triggerContext);
}

});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,50 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import io.vertx.core.Future;
import io.github.zero88.schedulerx.impl.DefaultTriggerEvaluator;

/**
* Represents for the trigger evaluator to assess whether the trigger is able to run
* Represents for the trigger evaluator to assess in 2 cases:
* <ul>
* <li>if the trigger is can run before each execution round is started.</li>
* <li>if the trigger should stop executing immediately after one round of execution begins.</li>
* </ul>
*
* @see BeforeTriggerEvaluator
* @see AfterTriggerEvaluator
* @since 2.0.0
*/
public interface TriggerEvaluator {
public interface TriggerEvaluator extends BeforeTriggerEvaluator, AfterTriggerEvaluator {

/**
* Verify if the trigger can run before each execution round is started.
* Create a trigger evaluator with the before evaluator
*
* @param trigger the trigger
* @param triggerContext the trigger context
* @param externalId the job external id
* @return a future of the trigger context that is evaluated
* @return new trigger evaluator instance
* @see BeforeTriggerEvaluator
*/
@NotNull Future<TriggerContext> beforeTrigger(@NotNull Trigger trigger, @NotNull TriggerContext triggerContext,
@Nullable Object externalId);
static TriggerEvaluator byBefore(BeforeTriggerEvaluator beforeEvaluator) { return create(beforeEvaluator, null); }

/**
* Verify if the trigger should stop executing immediately after one round of execution begins.
* Create a trigger evaluator with the after evaluator
*
* @param round the current execution round
* @since 2.0.0
* @return new trigger evaluator instance
* @see AfterTriggerEvaluator
*/
@NotNull Future<TriggerContext> afterTrigger(@NotNull Trigger trigger, @NotNull TriggerContext triggerContext,
@Nullable Object externalId, long round);
static TriggerEvaluator byAfter(AfterTriggerEvaluator afterEvaluator) { return create(null, afterEvaluator); }

/**
* Chain another evaluator
* Create a trigger evaluator with the before and after evaluator
*
* @return new trigger evaluator instance
* @see BeforeTriggerEvaluator
* @see AfterTriggerEvaluator
*/
static TriggerEvaluator create(BeforeTriggerEvaluator beforeEvaluator, AfterTriggerEvaluator afterEvaluator) {
return DefaultTriggerEvaluator.init(beforeEvaluator, afterEvaluator);
}

/**
* Chain with another trigger evaluator.
*
* @param another another evaluator
* @return a reference to this for fluent API
Expand Down
18 changes: 4 additions & 14 deletions core/src/test/java/io/github/zero88/schedulerx/SchedulerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,18 @@
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import io.github.zero88.schedulerx.impl.DefaultTriggerEvaluator;
import io.github.zero88.schedulerx.trigger.CronScheduler;
import io.github.zero88.schedulerx.trigger.CronTrigger;
import io.github.zero88.schedulerx.trigger.EventScheduler;
import io.github.zero88.schedulerx.trigger.EventTrigger;
import io.github.zero88.schedulerx.trigger.IntervalScheduler;
import io.github.zero88.schedulerx.trigger.IntervalTrigger;
import io.github.zero88.schedulerx.trigger.Trigger;
import io.github.zero88.schedulerx.trigger.TriggerContext;
import io.github.zero88.schedulerx.trigger.TriggerEvaluator;
import io.github.zero88.schedulerx.trigger.predicate.EventTriggerPredicate;
import io.vertx.core.Future;
Expand Down Expand Up @@ -184,15 +179,10 @@ void test_scheduler_should_timeout_in_evaluation(Vertx vertx, VertxTestContext t
.setTestContext(testContext)
.setMisfire(timeoutAsserter)
.build();
final TriggerEvaluator evaluator = new DefaultTriggerEvaluator() {
@Override
protected Future<TriggerContext> internalBeforeTrigger(@NotNull Trigger trigger,
@NotNull TriggerContext triggerContext,
@Nullable Object externalId) {
TestUtils.block(runningTime, testContext);
return Future.succeededFuture(triggerContext);
}
};
final TriggerEvaluator evaluator = TriggerEvaluator.byBefore((trigger, triggerContext, externalId) -> {
TestUtils.block(runningTime, testContext);
return Future.succeededFuture(triggerContext);
});
IntervalScheduler.builder()
.setVertx(vertx)
.setMonitor(asserter)
Expand Down

0 comments on commit 36bc21d

Please sign in to comment.