Search code examples
springspring-bootspring-scheduled

Schedule a task with Cron which allows dynamic update


I use sprint boot 1.3, spring 4.2

In this class

@Service
public class PaymentServiceImpl implements PaymentService {
    ....
    @Transactional
    @Override
    public void processPayment() {
        List<Payment> payments = paymentRepository.findDuePayment();
        processCreditCardPayment(payments);
    }
}

I would like to call processPayment every x moment.

This x moment is set in a database. The user can modify it.

So i think i can't use anotation.

I started to this this

@EntityScan(basePackageClasses = {MyApp.class,     Jsr310JpaConverters.class})
@SpringBootApplication
@EnableCaching
@EnableScheduling
public class MyApp {

    @Autowired
    private DefaultConfigService defaultConfigService;

    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }

    @Bean
    public TaskScheduler poolScheduler() {
        SimpleAsyncTaskExecutor taskScheduler = new SimpleAsyncTaskExecutor();

        DefaultConfigDto defaultConfigDto = defaultConfigService.getByFieldName("payment-cron-task");
        String cronTabExpression = "0 0 4 * * ?";
        if (defaultConfigDto != null && !defaultConfigDto.getFieldValue().isEmpty()) {
            cronTabExpression = "0 0 4 * * ?";
        }

        appContext.getBean("scheduler");

        taskScheduler.schedule(task, new CronTrigger(cronTabExpression));
        return scheduler;
    }

Maybe it's not the good way.

Any suggestion?

Don't know if to get my context if i need to create a property like

@Autowired
ConfigurableApplicationContext context;

and after in the main

public static void main(String[] args) {
        context = SpringApplication.run(MyApp.class, args);
}

Solution

  • Looking at the question seems like you want to update the scheduler, without restart.

    The code you have shared only ensures the config is picked from DB, but it will not refresh without application restart.

    The following code will use the default scheduler available in the spring context and dynamically compute the next execution time based on the available cron setting in the DB:

    Here is the sample code:

    import java.util.Date;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.Trigger;
    import org.springframework.scheduling.TriggerContext;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.scheduling.annotation.SchedulingConfigurer;
    import org.springframework.scheduling.config.ScheduledTaskRegistrar;
    import org.springframework.scheduling.support.CronTrigger;
    
    @SpringBootApplication
    @EnableScheduling
    public class Perses implements SchedulingConfigurer {
        private static final Logger log = LoggerFactory.getLogger(Perses.class);
       
        @Autowired
        private DefaultConfigService defaultConfigService;
    
        @Autowired
        private PaymentService paymentService;
    
        public static void main(String[] args) {
            SpringApplication.run(Perses.class, args);
        }
    
        private String cronConfig() {
            String cronTabExpression = "*/5 * * * * *";
            if (defaultConfigDto != null && !defaultConfigDto.getFieldValue().isEmpty()) {
                cronTabExpression = "0 0 4 * * ?";
            }
            return cronTabExpression;
        }
    
        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
            taskRegistrar.addTriggerTask(new Runnable() {
                @Override
                public void run() {
                    paymentService.processPayment();
                }
            }, new Trigger() {
                @Override
                public Date nextExecutionTime(TriggerContext triggerContext) {
                    String cron = cronConfig();
                    log.info(cron);
                    CronTrigger trigger = new CronTrigger(cron);
                    Date nextExec = trigger.nextExecutionTime(triggerContext);
                    return nextExec;
                }
            });
        }
    }