8

I'm investigating using @Scheduled at a fixed rate where in some configurable circumstances the scheduled job should never be run.

The documentation doesn't mention this but the default values for fixedDelay() and fixedDelayString() are -1 and "" respectively. Can these be used to reliably ensure that the scheduled method doesn't fire?

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208

2 Answers2

7

You can not. When you set the fixedDelay attribute to -1 or attempt use @Scheduled without specifying a valid value for any of its attributes, Spring will complain that no attribute is set:

Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required

You can verify this behavior by going through the source code of ScheduledAnnotationBeanPostProcessor#processScheduled.

It contains logic like:

boolean processScheduled = false;

// ...

if (fixedRate >= 0) {
    Assert.isTrue(!processedSchedule, errorMessage);
    processedSchedule = true;
    this.registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay));
}

// ...

Assert.isTrue(processedSchedule, errorMessage);

Take a look at this SO post for some options for conditionally disabling @Scheduled.

Community
  • 1
  • 1
Bohuslav Burghardt
  • 33,626
  • 7
  • 114
  • 109
  • Oh, that's a shame - thanks for looking into it. I guess one possible workaround not mentioned in the post you linked might be to set extremely high (i.e. the max `long`) values for `initialDelay` and `fixedDelay` so they are never actually reached. This may work in practice but just seems a bit wrong to have to resort to this and a shame that Spring didn't provide a "never" option. – Steve Chambers Oct 05 '15 at 11:28
  • 2
    @SteveChambers Yes, that seems like a bit of a hack. Plus if you were to retrieve the value from configuration and set it using `fixedDelayStr`, it would be parsed using `Integer.parseInt` not `Long.parseLong`, so setting it to max value of long would fail :) ... I will report it later on Spring JIRA. – Bohuslav Burghardt Oct 05 '15 at 11:31
  • Oh dear, it seems `fixedDelayStr` is out of the question for this method then as the max integer is 2147483647, which (if my Google-assisted calculations are correct) in milliseconds equates to just 3 and a half weeks - bit different to the 292471208 years I think a `long` would allow! – Steve Chambers Oct 05 '15 at 11:36
  • 1
    @SteveChambers Edit: the parsing seems to be already fixed (at least in master, probably in 4.2 too). However the current Spring version I'm using (4.1.7) still has this problem. – Bohuslav Burghardt Oct 05 '15 at 12:06
  • Thanks @Bohuslav. Unfortunately we're using 4.17 too - might have to see if it's possible to migrate... – Steve Chambers Oct 05 '15 at 12:56
  • Looks like without the upgrade another option would be a cron expression. [This answer](http://stackoverflow.com/questions/13835221#13938099) relates to Quartz but would expect something simple like `0 0 0 1 1 ? 2099` should do the job (and am willing to take the hit on the "year 2099 bug"!) – Steve Chambers Oct 05 '15 at 13:05
  • Oh dear, again maybe not - need milliseconds precision, which unfortunately cron doesn't seem to provide. – Steve Chambers Oct 05 '15 at 13:19
1

As mentioned in spring docs, you can specify "-" to disable the triggering of the task:

CRON_DISABLED: A special cron expression value that indicates a disabled trigger: "-".

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Scheduled.html#CRON_DISABLED

Huseyin Yagli
  • 9,896
  • 6
  • 41
  • 50