30
30
import io .github .zero88 .schedulerx .trigger .TriggerCondition .ReasonCode ;
31
31
import io .github .zero88 .schedulerx .trigger .TriggerCondition .TriggerStatus ;
32
32
import io .github .zero88 .schedulerx .trigger .TriggerContext ;
33
+ import io .github .zero88 .schedulerx .trigger .TriggerEvaluator ;
34
+ import io .github .zero88 .schedulerx .trigger .rule .TriggerRule ;
33
35
import io .vertx .core .Future ;
34
36
import io .vertx .core .Promise ;
35
37
import io .vertx .core .Vertx ;
@@ -56,21 +58,23 @@ public abstract class AbstractScheduler<IN, OUT, T extends Trigger> implements S
56
58
private final @ NotNull JobData <IN > jobData ;
57
59
private final @ NotNull Job <IN , OUT > job ;
58
60
private final @ NotNull T trigger ;
61
+ private final @ NotNull TriggerEvaluator evaluator ;
59
62
private final @ NotNull TimeoutPolicy timeoutPolicy ;
60
63
private final Lock lock = new ReentrantLock ();
61
64
private boolean didStart = false ;
62
65
private boolean didTriggerValidation = false ;
63
66
private IllegalArgumentException invalidTrigger ;
64
67
65
- protected AbstractScheduler (@ NotNull Vertx vertx , @ NotNull SchedulingMonitor < OUT > monitor ,
66
- @ NotNull JobData < IN > jobData , @ NotNull Job < IN , OUT > job , @ NotNull T trigger ,
67
- @ NotNull TimeoutPolicy timeoutPolicy ) {
68
+ protected AbstractScheduler (@ NotNull Job < IN , OUT > job , @ NotNull JobData < IN > jobData ,
69
+ @ NotNull TimeoutPolicy timeoutPolicy , @ NotNull SchedulingMonitor < OUT > monitor ,
70
+ @ NotNull T trigger , @ NotNull TriggerEvaluator evaluator , @ NotNull Vertx vertx ) {
68
71
this .job = job ;
69
72
this .jobData = jobData ;
70
73
this .timeoutPolicy = timeoutPolicy ;
71
74
this .vertx = vertx ;
72
75
this .trigger = trigger ;
73
76
this .monitor = monitor ;
77
+ this .evaluator = new InternalTriggerEvaluator (this ).andThen (evaluator );
74
78
this .state = new SchedulerStateImpl <>();
75
79
}
76
80
@@ -170,23 +174,6 @@ protected final void doStop(long timerId, TriggerContext context) {
170
174
*/
171
175
protected abstract void unregisterTimer (long timerId );
172
176
173
- /**
174
- * Check a trigger kickoff context whether to be able to run new execution or not
175
- */
176
- protected final TriggerContext shouldRun (@ NotNull TriggerContext kickOffContext ) {
177
- log (Instant .now (), "On evaluate" );
178
- if (state .pending ()) {
179
- return TriggerContextFactory .skip (kickOffContext , ReasonCode .NOT_YET_SCHEDULED );
180
- }
181
- if (state .completed ()) {
182
- return TriggerContextFactory .skip (kickOffContext , ReasonCode .ALREADY_STOPPED );
183
- }
184
- if (state .executing ()) {
185
- return TriggerContextFactory .skip (kickOffContext , ReasonCode .JOB_IS_RUNNING );
186
- }
187
- return evaluateTriggerRule (kickOffContext );
188
- }
189
-
190
177
/**
191
178
* Check a trigger context whether to be able to stop by configuration or force stop
192
179
*/
@@ -199,23 +186,6 @@ protected final TriggerContext shouldStop(@NotNull TriggerContext triggerContext
199
186
: triggerContext ;
200
187
}
201
188
202
- /**
203
- * Evaluate a trigger kickoff context on trigger rule
204
- */
205
- protected TriggerContext evaluateTriggerRule (@ NotNull TriggerContext triggerContext ) {
206
- if (!triggerContext .isKickoff ()) {
207
- throw new IllegalStateException ("Trigger condition status must be " + TriggerStatus .KICKOFF );
208
- }
209
- final Instant firedAt = Objects .requireNonNull (triggerContext .firedAt (),
210
- "Kickoff context is missing a fired at time" );
211
- if (trigger ().rule ().isExceeded (firedAt )) {
212
- return TriggerContextFactory .stop (triggerContext , ReasonCode .STOP_BY_CONFIG );
213
- }
214
- return trigger ().shouldExecute (firedAt )
215
- ? TriggerContextFactory .ready (triggerContext )
216
- : TriggerContextFactory .skip (triggerContext , ReasonCode .CONDITION_IS_NOT_MATCHED );
217
- }
218
-
219
189
/**
220
190
* Register a timer id in internal state and increase tick time when the system timer fires
221
191
*
@@ -232,9 +202,9 @@ protected final long onFire(long timerId) {
232
202
protected final void onProcess (WorkerExecutor workerExecutor , TriggerContext ctx ) {
233
203
log (Objects .requireNonNull (ctx .firedAt ()), "On fire" );
234
204
final Duration timeout = timeoutPolicy ().evaluationTimeout ();
235
- this .<TriggerContext >executeBlocking (workerExecutor ,
236
- p -> wrapTimeout ( timeoutPolicy (). evaluationTimeout (), p ). complete (
237
- shouldRun ( ctx )))
205
+ this .<TriggerContext >executeBlocking (workerExecutor , p -> this . wrapTimeout ( timeout , p )
206
+ . handle ( evaluator . beforeRun ( trigger , ctx ,
207
+ jobData . externalId () )))
238
208
.onSuccess (context -> onTrigger (workerExecutor , context ))
239
209
.onFailure (t -> onMisfire (TriggerContextFactory .skip (ctx , t instanceof TimeoutException
240
210
? ReasonCode .EVALUATION_TIMEOUT
@@ -387,4 +357,44 @@ private <R> Promise<R> wrapTimeout(Duration timeout, Promise<R> promise) {
387
357
return new TimeoutBlock (vertx , timeout ).wrap (promise );
388
358
}
389
359
360
+ @ SuppressWarnings ("rawtypes" )
361
+ private static class InternalTriggerEvaluator extends AbstractTriggerEvaluator {
362
+
363
+ private final AbstractScheduler scheduler ;
364
+
365
+ private InternalTriggerEvaluator (AbstractScheduler scheduler ) { this .scheduler = scheduler ; }
366
+
367
+ @ Override
368
+ protected Future <TriggerContext > internalCheck (@ NotNull Trigger trigger , @ NotNull TriggerContext ctx ,
369
+ @ Nullable Object externalId ) {
370
+ if (!ctx .isKickoff ()) {
371
+ throw new IllegalStateException ("Trigger condition status must be " + TriggerStatus .KICKOFF );
372
+ }
373
+ return Future .succeededFuture (doCheck (ctx ));
374
+ }
375
+
376
+ @ NotNull
377
+ private TriggerContext doCheck (TriggerContext ctx ) {
378
+ scheduler .log (Instant .now (), "On evaluate" );
379
+ if (scheduler .state .pending ()) {
380
+ return TriggerContextFactory .skip (ctx , ReasonCode .NOT_YET_SCHEDULED );
381
+ }
382
+ if (scheduler .state .completed ()) {
383
+ return TriggerContextFactory .skip (ctx , ReasonCode .ALREADY_STOPPED );
384
+ }
385
+ if (scheduler .state .executing ()) {
386
+ return TriggerContextFactory .skip (ctx , ReasonCode .JOB_IS_RUNNING );
387
+ }
388
+ final Instant firedAt = Objects .requireNonNull (ctx .firedAt ());
389
+ final TriggerRule rule = scheduler .trigger ().rule ();
390
+ if (rule .isExceeded (firedAt )) {
391
+ return TriggerContextFactory .stop (ctx , ReasonCode .STOP_BY_CONFIG );
392
+ }
393
+ return rule .satisfy (firedAt )
394
+ ? TriggerContextFactory .ready (ctx )
395
+ : TriggerContextFactory .skip (ctx , ReasonCode .CONDITION_IS_NOT_MATCHED );
396
+ }
397
+
398
+ }
399
+
390
400
}
0 commit comments