Scheduling a Job With Spring Programmatically (With Fixedrate Set Dynamically)

Scheduling a job with Spring programmatically (with fixedRate set dynamically)

Using a Trigger you can calculate the next execution time on the fly.

Something like this should do the trick (adapted from the Javadoc for @EnableScheduling):

@Configuration
@EnableScheduling
public class MyAppConfig implements SchedulingConfigurer {

@Autowired
Environment env;

@Bean
public MyBean myBean() {
return new MyBean();
}

@Bean(destroyMethod = "shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(100);
}

@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
taskRegistrar.addTriggerTask(
new Runnable() {
@Override public void run() {
myBean().getSchedule();
}
},
new Trigger() {
@Override public Date nextExecutionTime(TriggerContext triggerContext) {
Calendar nextExecutionTime = new GregorianCalendar();
Date lastActualExecutionTime = triggerContext.lastActualExecutionTime();
nextExecutionTime.setTime(lastActualExecutionTime != null ? lastActualExecutionTime : new Date());
nextExecutionTime.add(Calendar.MILLISECOND, env.getProperty("myRate", Integer.class)); //you can get the value from wherever you want
return nextExecutionTime.getTime();
}
}
);
}
}

How to change Spring's @Scheduled fixedDelay at runtime?

You can use a Trigger to dynamically set the next execution time.

See my answer to Scheduling a job with Spring programmatically for details.

How to add new schedule job dynamically with Spring

If you want to dynamically schedule tasks you can do it without spring by using ExecutorService in particular ScheduledThreadPoolExecutor

Runnable task  = () -> doSomething();
ScheduledExecutorService executor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
// Schedule a task that will be executed in 120 sec
executor.schedule(task, 120, TimeUnit.SECONDS);

// Schedule a task that will be first run in 120 sec and each 120sec
// If an exception occurs then it's task executions are canceled.
executor.scheduleAtFixedRate(task, 120, 120, TimeUnit.SECONDS);

// Schedule a task that will be first run in 120 sec and each 120sec after the last execution
// If an exception occurs then it's task executions are canceled.
executor.scheduleWithFixedDelay(task, 120, 120, TimeUnit.SECONDS);

With spring you can rely on the Task and Scheduling API

public class MyBean {

private final TaskScheduler executor;

@Autowired
public MyBean(TaskScheduler taskExecutor) {
this.executor = taskExecutor;
}

public void scheduling(final Runnable task) {
// Schedule a task to run once at the given date (here in 1minute)
executor.schedule(task, Date.from(LocalDateTime.now().plusMinutes(1)
.atZone(ZoneId.systemDefault()).toInstant()));

// Schedule a task that will run as soon as possible and every 1000ms
executor.scheduleAtFixedRate(task, 1000);

// Schedule a task that will first run at the given date and every 1000ms
executor.scheduleAtFixedRate(task, Date.from(LocalDateTime.now().plusMinutes(1)
.atZone(ZoneId.systemDefault()).toInstant()), 1000);

// Schedule a task that will run as soon as possible and every 1000ms after the previous completion
executor.scheduleWithFixedDelay(task, 1000);

// Schedule a task that will run as soon as possible and every 1000ms after the previous completion
executor.scheduleWithFixedDelay(task, Date.from(LocalDateTime.now().plusMinutes(1)
.atZone(ZoneId.systemDefault()).toInstant()), 1000);

// Schedule a task with the given cron expression
executor.schedule(task, new CronTrigger("*/5 * * * * MON-FRI"));
}
}

And you can provide your own trigger by implementing Trigger

Don't forget to enable the scheduling by usin @EnableScheduling on configuration class.

About listening to directory content you can use WatchService. Something like:

final Path myDir = Paths.get("my/directory/i/want/to/monitor");
final WatchService watchService = FileSystems.getDefault().newWatchService();
// listen to create event in the directory
myDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
// Infinite loop don't forget to run this in a Thread
for(;;) {
final WatchKey key = watchService.take();
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent<Path> watchEvent = (WatchEvent<Path>) event;
Path newFilePath = myDir.resolve(watchEvent.context());
//do something with the newFilePath
}
// To keep receiving event
key.reset();
}

Take a look at this article: Watching a Directory for Changes for more details.



Related Topics



Leave a reply



Submit