Skip to main content

spring_boot_starter_scheduling 0.1.4 copy "spring_boot_starter_scheduling: ^0.1.4" to clipboard
spring_boot_starter_scheduling: ^0.1.4 copied to clipboard

Scheduling starter for spring_boot_dart: @Scheduled methods with fixed rate, fixed delay or cron expressions, a TaskScheduler bean, stopped with the context.

spring_boot_starter_scheduling #

Scheduled tasks for spring_boot_dart applications, like Spring's @Scheduled: annotate a bean method and it runs every few seconds, after each run with a pause, or at cron times. Tasks stop when the context closes.

Installation #

dependencies:
  spring_boot_dart: ^0.1.0
  spring_boot_starter_scheduling: ^0.1.0

dev_dependencies:
  build_runner: ^2.17.0
  spring_core_dart_generator: ^0.1.0   # required: makes @Scheduled methods callable
dart run build_runner build

That is all: the starter is found automatically (no @EnableScheduling).

Quick example #

import 'package:spring_boot_starter_scheduling/spring_boot_starter_scheduling.dart';

@Component()
class Reports {
  Reports(this.repository);
  final ReportRepository repository;

  @Scheduled(fixedRate: Duration(minutes: 5))
  void refreshCache() => repository.refresh();

  @Scheduled(fixedDelay: Duration(seconds: 30))
  Future<void> syncWithServer() async => await repository.sync();

  @Scheduled(cron: '0 0 9 * * MON-FRI') // 9:00 on working days
  void morningDigest() => repository.sendDigest();
}

Start the application as usual (runApplication(args)); the tasks start once the context is ready.

@Scheduled #

Give exactly one of cron, fixedRate or fixedDelay.

Attribute Meaning Example
fixedRate start every period (measured between starts) fixedRate: Duration(minutes: 5)
fixedDelay wait this long after each run completes fixedDelay: Duration(seconds: 30)
initialDelay wait before the first run (not with cron) initialDelay: Duration(seconds: 10)
cron run at cron times; - switches the task off cron: '0 */15 * * * *'
zone time zone of cron: leave out for local time, or 'UTC' zone: 'UTC'
fixedRateString, fixedDelayString, initialDelayString the same as text, with ${...} placeholders and Spring Boot durations fixedRateString: r'${reports.rate:5m}'

Rules:

  • The method must be public and take no parameters. It may return a Future: the run counts as finished when the future completes.
  • Several @Scheduled on one method give several schedules.
  • Only singleton beans are scheduled (@Scope('prototype') beans are ignored with a warning).
  • A wrong attribute (two kinds, a bad cron, an unknown zone, a missing property) stops the startup with a message naming Class.method.
  • The method is called on the bean as other beans see it, so AOP advice (@Around, @Cacheable, ...) applies.

Cron expressions #

Six fields, like Spring (not five like Unix cron):

second minute hour day-of-month month day-of-week
Expression Runs
0 * * * * * every minute, at second 0
*/10 * * * * * every 10 seconds
0 */15 * * * * every 15 minutes
0 0 * * * * every hour
0 0 9-17 * * MON-FRI every hour from 9 to 17 on working days
0 30 8 * * * 8:30 every day
0 0 0 1 * * midnight on the 1st of each month
0 0 18 L * * 18:00 on the last day of the month
0 0 12 LW * * noon on the last working day of the month
0 0 10 15W * * 10:00 on the working day nearest to the 15th
0 0 20 ? * FRIL 20:00 on the last Friday of the month
0 0 9 ? * MON#1 9:00 on the first Monday of the month
0 0 0 25 DEC * midnight on December 25th
@hourly, @daily (@midnight), @weekly, @monthly, @yearly (@annually) the usual macros
  • Values: *, 5, lists 1,15,30, ranges 9-17, steps */5, 0-30/10, 5/15 (from 5, every 15). Months JAN-DEC, days SUN-SAT (0 and 7 are Sunday), case-insensitive. ? means "any" in the day fields.
  • As in Spring, a day must match both day fields, and ranges cannot wrap around (FRI-MON is an error: write FRI-SAT,SUN-MON).
  • Local time follows the wall clock: a time inside the hour skipped when clocks go forward runs at the first valid time after it; a time inside the hour repeated when clocks go back runs once.

Check an expression in code:

final cron = CronExpression.parse('0 0 9 * * MON-FRI');
print(cron.next(DateTime.now())); // the next run
CronExpression.isValid('0 0 25 * * *'); // false: hour 25

Configuration from properties #

Every text attribute resolves placeholders, so schedules can live in application.properties and change per profile:

@Scheduled(fixedRateString: r'${reports.rate:5m}')
void refresh() { ... }

@Scheduled(cron: r'${reports.cleanup-cron:-}') // off unless configured
void cleanup() { ... }
# lib/resources/application.properties
reports.rate=10m
reports.cleanup-cron=0 0 3 * * *

Durations: 500 (milliseconds), 10s, 5m, 2h, 1d, PT1H30M.

Property Default Meaning
spring.task.scheduling.enabled true false switches scheduling off (no TaskScheduler, no tasks)

Scheduling in code: TaskScheduler #

Inject the TaskScheduler bean to schedule work yourself:

@Service()
class Reminders {
  Reminders(this.scheduler);
  final TaskScheduler scheduler;

  ScheduledTask remindAt(DateTime at, String text) =>
      scheduler.schedule(() => notify(text), OneShotTrigger(at));

  ScheduledTask poll() => scheduler.scheduleWithFixedDelay(
    checkInbox,
    const Duration(seconds: 30),
  );
}

final task = reminders.poll();
print(task.nextExecution);
task.cancel();

Triggers: PeriodicTrigger (fixed rate or delay), CronTrigger, OneShotTrigger, or your own Trigger. Declare your own TaskScheduler bean to replace the default TimerTaskScheduler.

Asynchronous tasks and overlapping #

Everything runs on Dart's event loop, so a task never runs twice at the same time:

  • fixedDelay: the pause starts when the run (its Future) completes.
  • fixedRate: when a run takes longer than the period, the next run starts right after it, once; missed runs are not caught up.
  • cron: the next time is computed after the run, so times missed during a long run are skipped.

Errors #

An exception (thrown or from the returned Future) is logged at error level to the spring.scheduling logger, with the task name; the task keeps its schedule. Handle errors in the method if you need retries or alerts.

Testing #

Scheduled methods run in springBootTest too. To keep tests deterministic, either switch scheduling off and call the methods directly:

final app = springBootTest(
  springApplication,
  properties: {'spring.task.scheduling.enabled': false},
);

test('refresh', () => app.getBean<Reports>().refreshCache());

or replace the scheduler with one on a controlled clock (TimerTaskScheduler(now: ..., createTimer: ...)) through BeanOverride. ScheduledAnnotationBeanPostProcessor.scheduledTasks lists what is scheduled.

Hot reload #

Tasks belong to the context: a hot-reload restart closes it (cancelling every task) and the new context schedules the methods of the new code.

Differences from Spring #

  • No @EnableScheduling: the dependency switches scheduling on; spring.task.scheduling.enabled=false switches it off.
  • Time zones: local time or UTC only (Dart has no time zone database).
  • Durations are Durations instead of numbers plus timeUnit.
  • Not yet: @Async, SchedulingConfigurer, scheduling of prototype beans.
0
likes
0
points
650
downloads

Publisher

verified publisherfarum-azula.org

Weekly Downloads

Scheduling starter for spring_boot_dart: @Scheduled methods with fixed rate, fixed delay or cron expressions, a TaskScheduler bean, stopped with the context.

Repository (GitHub)
View/report issues

Topics

#scheduling #cron #spring

License

unknown (license)

Dependencies

spring_boot_dart

More

Packages that depend on spring_boot_starter_scheduling