@@ -230,32 +230,55 @@ private boolean executeIfScheduled(final T doc,
230230 private boolean execute (final T doc ,
231231 final ExecutionSchedule executionSchedule ,
232232 final TaskContext taskContext ) {
233- final ExecutionTracker currentTracker = executionScheduleDao .getTracker (executionSchedule ).orElse (null );
233+ final ExecutionTracker currentTracker = executionScheduleDao .getTracker (executionSchedule )
234+ .orElse (null );
234235 final Schedule schedule = executionSchedule .getSchedule ();
235236 final ScheduleBounds scheduleBounds = executionSchedule .getScheduleBounds ();
236-
237237 // See if it is time to execute this query.
238238 final Instant executionTime = Instant .now ();
239239 final Trigger trigger = TriggerFactory .create (schedule );
240240
241241 final Instant effectiveExecutionTime ;
242242 if (currentTracker != null ) {
243- effectiveExecutionTime = Instant .ofEpochMilli (currentTracker .getNextEffectiveExecutionTimeMs ());
243+ final Instant startTime = NullSafe .get (
244+ scheduleBounds ,
245+ ScheduleBounds ::getStartTimeMs ,
246+ Instant ::ofEpochMilli );
247+ final Instant trackerTime = Instant .ofEpochMilli (currentTracker .getNextEffectiveExecutionTimeMs ());
248+ // User may have changed the start bound since the tracker was last updated, so if the new start
249+ // time is later, work from there
250+ effectiveExecutionTime = startTime != null && startTime .isAfter (trackerTime )
251+ ? trigger .getNextExecutionTimeAfter (startTime )
252+ : trackerTime ;
244253 } else {
245- if (scheduleBounds != null && scheduleBounds .getStartTimeMs () != null ) {
246- effectiveExecutionTime = Instant .ofEpochMilli (scheduleBounds .getStartTimeMs ());
247- } else {
248- effectiveExecutionTime = trigger .getNextExecutionTimeAfter (executionTime );
249- }
254+ // No tracker so base the next eff time off now
255+ effectiveExecutionTime = NullSafe .getOrElseGet (
256+ scheduleBounds ,
257+ ScheduleBounds ::getStartTimeMs ,
258+ Instant ::ofEpochMilli ,
259+ () -> trigger .getNextExecutionTimeAfter (executionTime ));
250260 }
251261
252262 // Calculate end bounds.
253- Instant endTime = Instant .MAX ;
254- if (scheduleBounds != null && scheduleBounds .getEndTimeMs () != null ) {
255- endTime = Instant .ofEpochMilli (scheduleBounds .getEndTimeMs ());
256- }
263+ final Instant endTime = NullSafe .getOrElse (
264+ scheduleBounds ,
265+ ScheduleBounds ::getEndTimeMs ,
266+ Instant ::ofEpochMilli ,
267+ Instant .MAX );
268+
269+ LOGGER .debug ("execute() - endTime: {}, executionTime: {}, " +
270+ "effectiveExecutionTime: {}, schedule: {}" ,
271+ endTime , executionTime , effectiveExecutionTime , schedule );
272+
273+ // bounds are inclusive
274+ if (effectiveExecutionTime != null
275+ && !effectiveExecutionTime .isAfter (executionTime )
276+ && !effectiveExecutionTime .isAfter (endTime )) {
277+
278+ LOGGER .debug ("execute() - Executing - endTime: {}, executionTime: {}, " +
279+ "effectiveExecutionTime: {}, schedule: {}" ,
280+ endTime , executionTime , effectiveExecutionTime , schedule );
257281
258- if (!effectiveExecutionTime .isAfter (executionTime ) && !effectiveExecutionTime .isAfter (endTime )) {
259282 taskContext .info (() -> "Executing schedule '" +
260283 executionSchedule .getName () +
261284 "' with effective time: " +
@@ -273,6 +296,10 @@ private boolean execute(final T doc,
273296 effectiveExecutionTime ,
274297 executionSchedule ,
275298 currentTracker ));
299+ } else {
300+ LOGGER .debug ("execute() - Skipping execution - endTime: {}, executionTime: {}, " +
301+ "effectiveExecutionTime: {}, schedule: {}" ,
302+ endTime , executionTime , effectiveExecutionTime , schedule );
276303 }
277304 return false ;
278305 }
@@ -368,5 +395,33 @@ private void info(final Supplier<String> messageSupplier) {
368395
369396 public record ExecutionResult (String status , String message ) {
370397
398+ private static final ExecutionResult EMPTY = new ExecutionResult (null , null );
399+
400+ public static final String STATUS_COMPLETE = ExecutionHistory .STATUS_COMPLETE ;
401+ public static final String STATUS_ERROR = ExecutionHistory .STATUS_ERROR ;
402+
403+ public ExecutionResult {
404+ if (status != null ) {
405+ if (!STATUS_COMPLETE .equals (status ) && !STATUS_ERROR .equals (status )) {
406+ throw new IllegalArgumentException ("Invalid status: " + status );
407+ }
408+ }
409+ if (message != null && status == null ) {
410+ throw new IllegalArgumentException (LogUtil .message (
411+ "Can't have non-null message '{}' with no status" , message ));
412+ }
413+ }
414+
415+ public static ExecutionResult empty () {
416+ return EMPTY ;
417+ }
418+
419+ public static ExecutionResult complete (final String message ) {
420+ return new ExecutionResult (STATUS_COMPLETE , message );
421+ }
422+
423+ public static ExecutionResult error (final String message ) {
424+ return new ExecutionResult (STATUS_ERROR , message );
425+ }
371426 }
372427}
0 commit comments