14

Is there a way to call a spring scheduled method (job) through a user interaction? I need to create a table with shown all jobs and the user should be able to execute them manually. For sure the jobs run automatically but the user should be able to start them manually.

@Configuration
@EnableScheduling
public class ScheduleConfiguration {

    @Bean
    public ScheduledLockConfiguration taskScheduler(LockProvider 
     lockProvider) {
        return ScheduledLockConfigurationBuilder
                .withLockProvider(lockProvider)
                .withPoolSize(15)
                .withDefaultLockAtMostFor(Duration.ofHours(3))
                .build();
    }

    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(dataSource);
    }
}

@Component
public class MyService {

    @Scheduled(fixedRateString = "1000")
    @SchedulerLock(name = "MyService.process", lockAtLeastFor = 30000)
    @Transactional
    public void process() {
        // do something
    }
}
Nkalian
  • 141
  • 1
  • 1
  • 5

1 Answers1

10

Here's an example using a TaskScheduler:

Creating a task which will be scheduled and invoked manually:

@Component
public class SomeTask implements Runnable {

    private static final Logger log = LoggerFactory.getLogger();

    @Autowired
    public SomeDAO someDao;

    @Override
    public void run() {
        // do stuff
    }
}

Creating TaskScheduler bean:

@Configuration
public class TaskSchedulerConfig {

    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(5);
        threadPoolTaskScheduler.setThreadNamePrefix("ThreadPoolTaskScheduler");
        return threadPoolTaskScheduler;
    }
}

Scheduling task for periodic execution:

@Component
public class ScheduledTasks {
    @Autowired private TaskScheduler taskScheduler;

    // Tasks
    @Autowired private SomeTask task1; // autowired in case the task has own autowired dependencies
    @Autowired private AnotherTask task2;

    @PostConstruct
    public void scheduleTasks() {
        taskScheduler.schedule(task1, new PeriodicTrigger(20, TimeUnit.SECONDS));
        taskScheduler.schedule(task2, new CronTrigger("0 0 4 1/1 * ? *"));
    }
}

Manually invoking a task via a http request:

@Controller
public class TaskController {

    @Autowired private TaskScheduler taskScheduler;

    // Tasks
    @Autowired private SomeTask task1;

    @RequestMapping(value = "/executeTask")
    public void executeTask() {
        taskScheduler.schedule(task1, new Date()); // schedule task for current time
    }
}
das Keks
  • 3,723
  • 5
  • 35
  • 57
  • If you manually invoke the task1 via http request, will the PeriodicTrigger for the same task be adjusted to avoid parallell run of the same task? – Ismar Slomic Feb 11 '19 at 08:57
  • No, as far as I know the triggers will work completely independent. – das Keks Feb 11 '19 at 09:08
  • Ok. Any idea on how to avoid running same tasks in parallel and reset the scheduled task when triggered manually? – Ismar Slomic Feb 11 '19 at 09:09
  • 1
    Not sure if this is the best way but when the job is invoked manually you could first cancel the `PeriodicTrigger` and after that create a new `PeriodicTrigger`. To cancel the scheduling you would have to save the returned ʼFutureʼ object of the schedule method. Sounds a bit messy but that's the only solution I have in mind right now. – das Keks Feb 11 '19 at 09:43
  • Thank you, @dasKeks! This helped me a lot while configuring the task. How can this be unit/integration tested? Is there any approach I can use? – Arthur Eirich Apr 25 '23 at 13:07