alex
alex

Reputation: 79

Best way to schedule tasks from database using Java (Spring)

I'm looking for frameworks to schedule a set of tasks populated in the Database

JPA entities look like this

@Entity
class Task extends Model {
    @NotNull
    @Min(1L)
    @Column(name = "interval_ms", nullable = false)
    Integer interval

    @NotNull
    String payload  

    @NotNull
    Boolean enabled
}

@Entity
class TaskResult extends Model {
    @ManyToOne(optional = false)
    Task task

    @Column(nullable = false)
    Boolean result

    @Column(nullable = false)
    String message
}

tasks should be executed every interval defined in the "interval" field, result should be written into TaskResult table

The purpose of task is to make a GET or POST request, so requests have to be pooled to avoid the situation when a lot of tasks start to execute in parallel.

I'm using spring boot.

what are best practices here?

Upvotes: 3

Views: 13518

Answers (1)

Pavel Stančík
Pavel Stančík

Reputation: 71

If you are using Spring Boot, you can use TaskExecutor bean and configure pool size http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-task-executor-usage Then use TaskScheduler to define, when the task should run. Event values for this parameter comes from database (ie. Object).

Once I created scheduler but I used Quartz. I created newJob's, which was triggered every 1 minute (but you can use also miliseconds) and searched EmailQueue in database, if email was found, it tries to send it, when error occured with sending, he do not delete email in the queue and writes into the LOG table details about an error. The scheduler (1 minute) was set up from database. In your case you should use: newJob(QuartzJob.class).withIntervalInMilliseconds

http://quartz-scheduler.org/api/2.2.0/org/quartz/SimpleScheduleBuilder.html#withIntervalInMilliseconds(long)

@Service
public class MyQuartz implements InitializingBean, DisposableBean {

    @Autowired
    StdSchedulerFactory stdSchedulerFactory;
    @Autowired
    TableConfiguration tableConfiguration;
    Scheduler sched = null;
    JobDetail job, job2;
    JobDetail[] jobs = new JobDetail[2];

    public void initIt() throws Exception {

        try {
            System.out.println("Shedulling a job...");
            sched = stdSchedulerFactory.getScheduler();
        } catch (SchedulerException e) {
            System.err.println("Could not create scheduler.");
            e.printStackTrace();
        }
        try {
            System.out.println("Starting scheduler");
            sched.start();
        } catch (SchedulerException e) {
            System.err.println("Could not start scheduler.");
            e.printStackTrace();
        }
        // define the job and tie it to our QuartzJob class
        job = newJob(QuartzJob.class).withIdentity("myJob", "group1").build();
        job2 = newJob(QuartzCronJob.class).withIdentity("myCronJob", "group2")
                .build();
        jobs[0] = job;
        // .. here I have more jobs ...
        // Trigger the job to run now, and then every 5 minutes

        Trigger trigger = newTrigger()
                .withIdentity("myTrigger", "group1")
                .startNow()
                .withSchedule(
                        simpleSchedule().withIntervalInMinutes(
                                tableConfiguration.getTimeInterval())
                                .repeatForever()).build();

        // ... more triggers also here
        // Tell quartz to schedule the job using our trigger
        try {
            sched.scheduleJob(job, trigger);
            System.out.println("..job schedulled.");
        } catch (SchedulerException e) {
            System.err.println("Could not schedulle a job.");
            e.printStackTrace();
        }

    }

    @Override
    public void destroy() throws Exception {

        try {
            System.out.println("Stopping scheduler...");
            for (int i = 0; i < jobs.length; i++) { // Destroying all jobs
                sched.deleteJob(jobs[i].getKey());
            }
            sched.shutdown(true); // Waiting for jobs to complete.
            System.out.println("...scheduler Terminated. Good Bye.");
        } catch (SchedulerException e) {
            System.err.println("ERROR, scheduler cannot be stopped.");
            e.printStackTrace();
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {

    }
}

and

@Service
@Transactional
public class QuartzCronJob implements Job {
    @Override
    public void execute(JobExecutionContext context)
            throws JobExecutionException {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = new GregorianCalendar();
        String schedulled = sdf.format(calendar.getTime());

        System.out.println("LIST now " + schedulled);
        List<EmailQueue> emails = emailQueueDao.findAllForToday(schedulled);

        if (emails != null) {
            for (EmailQueue email : emails) {
                // Send email:
                try {
                    sendmail.sendNotification(email.getFrom(), email.getTo(),
                            email.getSubject(), email.getMessage(), "Sched.");
                    // Delete email from queue:
                    emailQueueDao.delete(email.getId());
                    System.out.println("Email sucessfully sent and deleted.");
                } catch (Exception e) {
                    sendmail.logEmail(LoggerSeverity.ERROR,
                            "Could not send schedulled email", "Sched.");
                    System.err.println("Could not send schedulled email");
                }
            }
        } 
        // ... more code here, this is just a working sample...
    }
}

My code is not using pooling, but I did not retrieved more than 3 emails from database as it run once per minute :)

Upvotes: 5

Related Questions