202 lines
7.7 KiB
Java
202 lines
7.7 KiB
Java
package org.hso.ecommerce.controller.cronjob;
|
|
|
|
import org.hso.ecommerce.entities.cron.BackgroundJob;
|
|
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
|
|
import org.hso.ecommerce.repos.booking.BookingRepository;
|
|
import org.hso.ecommerce.repos.cronjob.BackgroundJobRepository;
|
|
import org.hso.ecommerce.repos.dashboard.DashboardSummaryRepository;
|
|
import org.hso.ecommerce.repos.shop.ArticleRepository;
|
|
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
|
|
import org.hso.ecommerce.repos.supplier.ArticleOfferRepository;
|
|
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
|
|
import org.hso.ecommerce.repos.supplier.SupplierRepository;
|
|
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.ui.Model;
|
|
import org.springframework.web.bind.annotation.GetMapping;
|
|
import org.springframework.web.bind.annotation.PathVariable;
|
|
import org.springframework.web.bind.annotation.PostMapping;
|
|
import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
|
import javax.annotation.PostConstruct;
|
|
import java.sql.Timestamp;
|
|
import java.util.*;
|
|
import java.util.Map.Entry;
|
|
|
|
@Component
|
|
@RequestMapping("intern/cronjobs")
|
|
class CronjobController {
|
|
private static final Logger log = LoggerFactory.getLogger(CronjobController.class);
|
|
|
|
private Map<String, ICronjob> cronjobs;
|
|
|
|
@Autowired
|
|
private final BackgroundJobRepository cronjobRepository = null;
|
|
|
|
@Autowired
|
|
final ArticleRepository articleRepository = null;
|
|
|
|
@Autowired
|
|
final ArticleOfferRepository articleOfferRepository = null;
|
|
|
|
@Autowired
|
|
final CustomerOrderRepository customerOrderRepository = null;
|
|
|
|
@Autowired
|
|
final BookingRepository bookingRepository = null;
|
|
|
|
@Autowired
|
|
final BookingAccountEntryRepository bookingAccountEntryRepository = null;
|
|
|
|
@Autowired
|
|
final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
|
|
|
|
@Autowired
|
|
final DashboardSummaryRepository dashboardSummaryRepository = null;
|
|
|
|
@Autowired
|
|
final SupplierRepository supplierRepository = null;
|
|
|
|
@Autowired
|
|
final SupplierOrderRepository supplierOrderRepository = null;
|
|
|
|
@Autowired
|
|
final Reorder reorderJob = null;
|
|
|
|
@Autowired
|
|
final DashboardCronjob dashboardCronjob = null;
|
|
|
|
@Autowired
|
|
final AutoSupplierPayment autoSupplierPaymentJob = null;
|
|
|
|
@PostConstruct
|
|
public void init() {
|
|
cronjobs = getCronjobs();
|
|
}
|
|
|
|
private Map<String, ICronjob> getCronjobs() {
|
|
HashMap<String, ICronjob> map = new HashMap<>();
|
|
|
|
// Register all existing cronjobs
|
|
map.put(BackgroundJob.JOB_REORDER, reorderJob);
|
|
map.put(BackgroundJob.JOB_DASHBOARD, dashboardCronjob);
|
|
map.put(BackgroundJob.JOB_SUPPLIER_AUTO_PAYMENT, autoSupplierPaymentJob);
|
|
|
|
return Collections.unmodifiableMap(map);
|
|
}
|
|
|
|
private ScheduledCronjob getNextCronjob() {
|
|
Calendar currentTime = new GregorianCalendar();
|
|
Iterable<BackgroundJob> jobs = cronjobRepository.findAll();
|
|
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);
|
|
}
|
|
|
|
try {
|
|
nextJob.cronjob.executeAt(nextJob.executionTime, this);
|
|
} catch (Throwable t) {
|
|
log.error("Failed to execute cronjob " + nextJob.cronjob.getClass() + ":");
|
|
t.printStackTrace();
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
class ManualCronjob {
|
|
public final String identifier;
|
|
public final String visibleName;
|
|
|
|
public ManualCronjob(String identifier, String visibleName) {
|
|
this.identifier = identifier;
|
|
this.visibleName = visibleName;
|
|
}
|
|
}
|
|
|
|
private List<ManualCronjob> listAllCronjobs() {
|
|
ArrayList<ManualCronjob> entries = new ArrayList<>();
|
|
for (Entry<String, ICronjob> job : cronjobs.entrySet()) {
|
|
entries.add(new ManualCronjob(job.getKey(), job.getValue().getDisplayName()));
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
@GetMapping("/")
|
|
public String cronjobOverview(Model model) {
|
|
model.addAttribute("jobs", listAllCronjobs());
|
|
return "intern/cronjobs/index";
|
|
}
|
|
|
|
@PostMapping("/run/{identifier}")
|
|
public String runCronjob(Model model, @PathVariable("identifier") String identifier) {
|
|
ICronjob jobToExecute = cronjobs.get(identifier);
|
|
if (jobToExecute != null) {
|
|
jobToExecute.executeAt(new GregorianCalendar(), this);
|
|
model.addAttribute("info",
|
|
String.format("Der Cronjob \"%s\" wurde ausgeführt.", jobToExecute.getDisplayName()));
|
|
} else {
|
|
model.addAttribute("error", "Der Cronjob konnte nicht gefunden werden.");
|
|
}
|
|
model.addAttribute("jobs", listAllCronjobs());
|
|
return "intern/cronjobs/index";
|
|
}
|
|
}
|