118 lines
4.6 KiB
Java
118 lines
4.6 KiB
Java
|
package org.hso.ecommerce.controller.cronjob;
|
||
|
|
||
|
import java.sql.Timestamp;
|
||
|
import java.util.Calendar;
|
||
|
import java.util.Collections;
|
||
|
import java.util.GregorianCalendar;
|
||
|
import java.util.HashMap;
|
||
|
import java.util.Map;
|
||
|
import java.util.Map.Entry;
|
||
|
import javax.annotation.PostConstruct;
|
||
|
import org.hso.ecommerce.action.cronjob.ICronjob;
|
||
|
import org.hso.ecommerce.action.cronjob.Reorder;
|
||
|
import org.hso.ecommerce.entities.cron.BackgroundJob;
|
||
|
import org.hso.ecommerce.repos.cronjob.BackgroundJobRepository;
|
||
|
import org.slf4j.Logger;
|
||
|
import org.slf4j.LoggerFactory;
|
||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||
|
import org.springframework.stereotype.Component;
|
||
|
|
||
|
class ScheduledCronjob {
|
||
|
public final Calendar executionTime;
|
||
|
public final ICronjob cronjob;
|
||
|
public final BackgroundJob model;
|
||
|
|
||
|
public ScheduledCronjob(Calendar executionTime, ICronjob cronjob, BackgroundJob model) {
|
||
|
this.executionTime = executionTime;
|
||
|
this.cronjob = cronjob;
|
||
|
this.model = model;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Component
|
||
|
class CronjobController {
|
||
|
private static final Logger log = LoggerFactory.getLogger(CronjobController.class);
|
||
|
|
||
|
private static final Map<String, ICronjob> cronjobs = getCronjobs();
|
||
|
|
||
|
@Autowired
|
||
|
private final BackgroundJobRepository cronjobRepository = null;
|
||
|
|
||
|
private static Map<String, ICronjob> getCronjobs() {
|
||
|
HashMap<String, ICronjob> map = new HashMap<>();
|
||
|
|
||
|
// Register all existing cronjobs
|
||
|
map.put(BackgroundJob.JOB_REORDER, new Reorder());
|
||
|
|
||
|
return Collections.unmodifiableMap(map);
|
||
|
}
|
||
|
|
||
|
private ScheduledCronjob getNextCronjob() {
|
||
|
Calendar currentTime = new GregorianCalendar();
|
||
|
Iterable<BackgroundJob> jobs = cronjobRepository.getAllJobs();
|
||
|
HashMap<String, BackgroundJob> alreadyExecuted = new HashMap<>();
|
||
|
for (BackgroundJob job : jobs) {
|
||
|
alreadyExecuted.put(job.jobName, job);
|
||
|
}
|
||
|
ScheduledCronjob earliestJob = null;
|
||
|
for (Entry<String, ICronjob> entry : cronjobs.entrySet()) {
|
||
|
ScheduledCronjob resultingJob;
|
||
|
BackgroundJob dbEntry = alreadyExecuted.get(entry.getKey());
|
||
|
if (dbEntry != null) {
|
||
|
Calendar previousExecution = new GregorianCalendar();
|
||
|
previousExecution.setTimeInMillis(dbEntry.lastExecution.getTime());
|
||
|
Calendar followingSchedule = entry.getValue().nextExecution((Calendar) previousExecution.clone());
|
||
|
Calendar lastSchedule = entry.getValue().previousExecution((Calendar) currentTime.clone());
|
||
|
if (lastSchedule.getTimeInMillis() > followingSchedule.getTimeInMillis()) {
|
||
|
// This happens, if more than one execution was missed.
|
||
|
// In this case, run the job only once.
|
||
|
followingSchedule = lastSchedule;
|
||
|
}
|
||
|
resultingJob = new ScheduledCronjob(followingSchedule, entry.getValue(), dbEntry);
|
||
|
} else {
|
||
|
// This cronjob has never been executed before.
|
||
|
Calendar lastScheduleTime = entry.getValue().previousExecution((Calendar) currentTime.clone());
|
||
|
BackgroundJob model = new BackgroundJob();
|
||
|
model.jobName = entry.getKey();
|
||
|
resultingJob = new ScheduledCronjob(lastScheduleTime, entry.getValue(), model);
|
||
|
}
|
||
|
|
||
|
// Look for the job with earliest executionTime - it will run next
|
||
|
if (earliestJob == null
|
||
|
|| resultingJob.executionTime.getTimeInMillis() < earliestJob.executionTime.getTimeInMillis()) {
|
||
|
earliestJob = resultingJob;
|
||
|
}
|
||
|
}
|
||
|
return earliestJob;
|
||
|
}
|
||
|
|
||
|
private void runCronjobExecutionLoop() {
|
||
|
Thread.currentThread().setName("Cronjob");
|
||
|
try {
|
||
|
while (true) {
|
||
|
ScheduledCronjob nextJob = getNextCronjob();
|
||
|
if (nextJob == null) {
|
||
|
// In case there are no cronjobs
|
||
|
return;
|
||
|
}
|
||
|
long waitingTime = nextJob.executionTime.getTimeInMillis() - System.currentTimeMillis();
|
||
|
if (waitingTime > 0) {
|
||
|
Thread.sleep(waitingTime);
|
||
|
}
|
||
|
|
||
|
nextJob.cronjob.executeAt(nextJob.executionTime);
|
||
|
|
||
|
nextJob.model.lastExecution = new Timestamp(nextJob.executionTime.getTimeInMillis());
|
||
|
cronjobRepository.save(nextJob.model);
|
||
|
}
|
||
|
} catch (InterruptedException e) {
|
||
|
log.error("The cronjob execution thread has been interrupted");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@PostConstruct
|
||
|
public void onPostConstruct() {
|
||
|
new Thread(this::runCronjobExecutionLoop).start();
|
||
|
}
|
||
|
}
|