Annotation Interface Scheduled
The annotated method must be void and take no parameters.
It must be inside a @Service or other managed bean.
Tasks are automatically cancelled when the owning plugin is unloaded.
TaskManager walks the class hierarchy when scanning for
@Scheduled methods, so an annotated method is still found on a ByteBuddy AOP proxy of
the declaring bean, and a method declared on a superclass of the bean -- an abstract base
service -- is scheduled too (as of 6.3.0, #532; before, only the bean class's own declared
methods were scanned). An overridden method is scheduled once, with the most derived
declaration's annotation; an override that does not carry @Scheduled itself is not
scheduled, because Java does not inherit annotations on methods.
Usage example:
@Service
public class InterestService {
@Scheduled(period = 36000, async = true) // Every 30 minutes, async
public void distributeInterest() {
// Framework calls this automatically
}
}
async = true is for literal timings only: a @Scheduled bound to a config key
(below) must be sync, and async = true together with a binding refuses the module at load
(#535 tracks async bindings).
Binding the timing to a config key (6.3.0)
Instead of a literal,periodKey() and delayKey() can name a
@ConfigEntry path on the module's own config entity, given by config(). The
value is read in seconds and multiplied by 20 for ticks, so an operator can tune the
interval without a second, hand-written scheduler in the module:
@Scheduled(config = EconomyConfig.class, periodKey = "interest.interval", delayKey = "interest.interval")
public void distributeInterest() { ... }
- The default lives only in the config field (
private int interestInterval = 1800;). Leave the literal it replaces unset:periodwithperiodKey,delaywithdelayKey. Setting both refuses the module at load. - Checked at load. The module alone is refused, naming the key and the value, when the
config class is not registered exactly once for the module (a directory
@ConfigEntitycannot be bound), the key matches no@ConfigEntrypath, the field is not anint,long,IntegerorLong, or the value is below 1 second,nullor aboveInteger.MAX_VALUE / 20seconds (about 3.4 years).0does not mean "off". - Inherited methods included. The binding is found on the same methods as an
unbound
@Scheduled: the bean class (after unwrapping an AOP proxy) and its superclasses, each overridden method once (#532). A bound method inherited from an abstract base is scheduled and checked at load like one the bean class declares. - Applied at
/ul reload, keeping the task's place in its cycle: the next run is the last run plus the new period (before the first run: the arm time plus the new delay), or the next tick if that moment has already passed. A reload never runs the task early and never postpones it by restarting its clock; a task whose value did not change is not touched. An invalid value on reload is not applied -- the running value is kept, a WARNING names the key, and the reload is reported as partial, naming the key, the refused value and the value kept, so/ul reloaddoes not reply plain success (#595). A panel edit takes effect at the next/ul reload. The reload step runs on the main thread only. - Panel edits are range-checked. A panel write that sets a bound key outside this
range (for example
0) is refused like a@Rangeviolation, and nothing is written. - No
@Rangeon a bound field. The binding's range above is the field's range. A module@Rangeon the same field would make an out-of-range reload throw from the config reload itself, which aborts the rest of that module's reload (issue #509) instead of keeping the running value. - Sync only. A bound method cannot be
async = true; that combination is refused at load. Bind a sync task and hand the heavy work toBukkit.getScheduler().runTaskAsynchronously(...)from its body. A sync task's runs happen on the main thread, where the reload also runs, which is what lets a reload keep the task's place in its cycle exactly. Literal (unbound)asynctasks are unaffected. Issue #535 tracks allowing async bindings. - Modules only. A binding on an External Plugin API bean is refused.
- Declare
api-version: 630in the module'splugin.yml. An older framework does not know these elements and silently ignores them -- the method would then run once at load instead of on the configured interval -- so the floor is what makes it refuse the module instead. 6.3.0 itself refuses a module that uses a binding while declaring a lowerapi-version, so the mistake shows up where it is made.
- Since:
- 6.2.0
-
Optional Element Summary
Optional ElementsModifier and TypeOptional ElementDescriptionbooleanRun on async thread instead of main server thread.Class<? extends AbstractConfigEntity> longInitial delay in ticks before first execution.@ConfigEntrypath whose value, in seconds (at least 1), is the initial delay.longRepeat interval in ticks.@ConfigEntrypath whose value, in seconds (at least 1), is the repeat interval.
-
Element Details
-
delay
long delayInitial delay in ticks before first execution. Default: 0. Leave unset whendelayKey()is set.- Returns:
- delay in ticks
- Default:
0L
-
period
long periodRepeat interval in ticks. -1 = run once after delay. Default: -1. Leave unset whenperiodKey()is set.- Returns:
- period in ticks
- Default:
-1L
-
async
boolean asyncRun on async thread instead of main server thread. Default: false- Returns:
- true if async
- Default:
false
-
config
Class<? extends AbstractConfigEntity> configConfig entity class whose@ConfigEntrykeysperiodKey()anddelayKey()name. It must be registered exactly once for the module, and the value is read from that same instance, which/ul reloadreloads in place. Default:AbstractConfigEntityitself, meaning unbound. See "Binding the timing to a config key" above.- Returns:
- the bound config entity class
- Since:
- 6.3.0
- Default:
com.ultikits.ultitools.abstracts.AbstractConfigEntity.class
-
periodKey
String periodKey@ConfigEntrypath whose value, in seconds (at least 1), is the repeat interval. The path is matched as@ConfigEntry(path = ...)declares it, or the field name when the path is empty. Requiresconfig(); excludesperiod(). Default: unbound.- Returns:
- the bound period key
- Since:
- 6.3.0
- Default:
""
-
delayKey
String delayKey@ConfigEntrypath whose value, in seconds (at least 1), is the initial delay. May name the same key asperiodKey()-- a task that must not run at load, such as a payout, waits one full interval first. Requiresconfig(); excludesdelay(). Default: unbound.- Returns:
- the bound delay key
- Since:
- 6.3.0
- Default:
""
-