Skip to content

Commit

Permalink
Denormalized job type and job status. Added version to base scheduled…
Browse files Browse the repository at this point in the history
… job properties
  • Loading branch information
mattwilshire committed Oct 11, 2024
1 parent a501246 commit cc04046
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 127 deletions.
49 changes: 26 additions & 23 deletions webapp/src/main/java/com/box/l10n/mojito/entity/ScheduledJob.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
package com.box.l10n.mojito.entity;

import com.box.l10n.mojito.json.ObjectMapper;
import com.box.l10n.mojito.rest.View;
import com.box.l10n.mojito.service.scheduledjob.ScheduledJobProperties;
import com.box.l10n.mojito.service.scheduledjob.ScheduledJobStatus;
import com.box.l10n.mojito.service.scheduledjob.ScheduledJobType;
import com.fasterxml.jackson.annotation.JsonView;
import jakarta.persistence.Basic;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.PostLoad;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import java.util.Date;
import org.hibernate.envers.Audited;

@Entity
@Table(name = "scheduled_job")
@Audited
public class ScheduledJob extends BaseEntity {
@Id private Long id;

@ManyToOne
@JoinColumn(name = "repository_id")
private Repository repository;

@Basic(optional = false)
@Column(name = "job_type")
@Enumerated(EnumType.STRING)
@JsonView(View.Repository.class)
private ScheduledJobType jobType;
@ManyToOne
@JoinColumn(name = "job_type")
private ScheduledJobTypeEntity jobType;

@Column(name = "cron")
private String cron;
Expand All @@ -42,29 +35,31 @@ public class ScheduledJob extends BaseEntity {
@Column(name = "properties")
private String propertiesString;

@Basic(optional = false)
@Column(name = "job_status")
@Enumerated(EnumType.STRING)
@JsonView(View.Repository.class)
private ScheduledJobStatus jobStatus;
@ManyToOne
@JoinColumn(name = "job_status")
private ScheduledJobStatusEntity jobStatus;

@Column(name = "start_date")
private Date startDate;

@Column(name = "end_date")
private Date endDate;

@Column(name = "enabled", nullable = false, columnDefinition = "TINYINT DEFAULT 1")
private Boolean enabled = true;

@PostLoad
public void deserializeProperties() {
ObjectMapper objectMapper = new ObjectMapper();
try {
this.properties = objectMapper.readValue(propertiesString, jobType.getPropertiesClass());
this.properties =
objectMapper.readValue(propertiesString, jobType.getEnum().getPropertiesClass());
} catch (Exception e) {
throw new RuntimeException(
"Failed to deserialize properties '"
+ propertiesString
+ "' for class: "
+ jobType.getPropertiesClass().getName(),
+ jobType.getEnum().getPropertiesClass().getName(),
e);
}
}
Expand All @@ -87,11 +82,11 @@ public void setRepository(Repository repository) {
this.repository = repository;
}

public ScheduledJobType getJobType() {
public ScheduledJobTypeEntity getJobType() {
return jobType;
}

public void setJobType(ScheduledJobType jobType) {
public void setJobType(ScheduledJobTypeEntity jobType) {
this.jobType = jobType;
}

Expand Down Expand Up @@ -126,11 +121,11 @@ public void setPropertiesString(String properties) {
this.propertiesString = properties;
}

public ScheduledJobStatus getJobStatus() {
public ScheduledJobStatusEntity getJobStatus() {
return jobStatus;
}

public void setJobStatus(ScheduledJobStatus jobStatus) {
public void setJobStatus(ScheduledJobStatusEntity jobStatus) {
this.jobStatus = jobStatus;
}

Expand All @@ -149,4 +144,12 @@ public Date getEndDate() {
public void setEndDate(Date endDate) {
this.endDate = endDate;
}

public Boolean getEnabled() {
return enabled;
}

public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.box.l10n.mojito.entity;

import static org.hibernate.envers.RelationTargetAuditMode.NOT_AUDITED;

import com.box.l10n.mojito.rest.View;
import com.box.l10n.mojito.service.scheduledjob.ScheduledJobStatus;
import com.fasterxml.jackson.annotation.JsonView;
import jakarta.persistence.Basic;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import org.hibernate.envers.Audited;

@Entity
@Table(name = "scheduled_job_status")
@Audited(targetAuditMode = NOT_AUDITED)
public class ScheduledJobStatusEntity extends BaseEntity {
@Id private Long id;

@Basic(optional = false)
@Column(name = "name")
@Enumerated(EnumType.STRING)
@JsonView(View.Repository.class)
private ScheduledJobStatus jobStatus;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.box.l10n.mojito.entity;

import static org.hibernate.envers.RelationTargetAuditMode.NOT_AUDITED;

import com.box.l10n.mojito.rest.View;
import com.box.l10n.mojito.service.scheduledjob.ScheduledJobType;
import com.fasterxml.jackson.annotation.JsonView;
import jakarta.persistence.Basic;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import org.hibernate.envers.Audited;

@Entity
@Table(name = "scheduled_job_type")
@Audited(targetAuditMode = NOT_AUDITED)
public class ScheduledJobTypeEntity extends BaseEntity {
@Id private Long id;

@Basic(optional = false)
@Column(name = "name")
@Enumerated(EnumType.STRING)
@JsonView(View.Repository.class)
private ScheduledJobType jobType;

@Override
public Long getId() {
return id;
}

@Override
public void setId(Long id) {
this.id = id;
}

public ScheduledJobType getEnum() {
return jobType;
}

public void setEnum(ScheduledJobType jobType) {
this.jobType = jobType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ public class ScheduledJobDTO {
public ScheduledJobDTO(ScheduledJob scheduledJob) {
this.id = scheduledJob.getId();
this.repository = scheduledJob.getRepository().getName();
this.jobType = scheduledJob.getJobType();
// this.jobType = scheduledJob.getJobType();
this.cron = scheduledJob.getCron();
this.properties = scheduledJob.getProperties();
this.jobStatus = scheduledJob.getJobStatus();
// this.jobStatus = scheduledJob.getJobStatus();
this.startDate = scheduledJob.getStartDate();
this.endDate = scheduledJob.getEndDate();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ public class ScheduledJobListener extends JobListenerSupport {
static Logger logger = LoggerFactory.getLogger(ScheduledJobListener.class);

private final ScheduledJobRepository scheduledJobRepository;
private final ScheduledJobStatusRepository scheduledJobStatusRepository;

public ScheduledJobListener(ScheduledJobRepository scheduledJobRepository) {
public ScheduledJobListener(
ScheduledJobRepository scheduledJobRepository,
ScheduledJobStatusRepository scheduledJobStatusRepository) {
this.scheduledJobRepository = scheduledJobRepository;
this.scheduledJobStatusRepository = scheduledJobStatusRepository;
}

@Override
Expand All @@ -28,7 +32,8 @@ public void jobToBeExecuted(JobExecutionContext context) {
ScheduledJob scheduledJob =
scheduledJobRepository.findByJobKey(context.getJobDetail().getKey());

scheduledJob.setJobStatus(ScheduledJobStatus.IN_PROGRESS);
scheduledJob.setJobStatus(
scheduledJobStatusRepository.findByEnum(ScheduledJobStatus.IN_PROGRESS));
scheduledJob.setStartDate(new Date());

scheduledJobRepository.save(scheduledJob);
Expand All @@ -43,10 +48,11 @@ public void jobWasExecuted(JobExecutionContext context, JobExecutionException jo
IScheduledJob jobInstance = (IScheduledJob) context.getJobInstance();

if (jobException == null) {
scheduledJob.setJobStatus(ScheduledJobStatus.SUCCEEDED);
scheduledJob.setJobStatus(
scheduledJobStatusRepository.findByEnum(ScheduledJobStatus.SUCCEEDED));
jobInstance.onSuccess(context);
} else {
scheduledJob.setJobStatus(ScheduledJobStatus.FAILED);
scheduledJob.setJobStatus(scheduledJobStatusRepository.findByEnum(ScheduledJobStatus.FAILED));
jobInstance.onFailure(context, jobException);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public class ScheduledJobManager {
@Autowired ThirdPartySyncJobsConfig thirdPartySyncJobsConfig;
@Autowired QuartzSchedulerManager schedulerManager;
@Autowired ScheduledJobRepository scheduledJobRepository;
@Autowired ScheduledJobStatusRepository scheduledJobStatusRepository;
@Autowired ScheduledJobTypeRepository scheduledJobTypeRepository;
@Autowired RepositoryRepository repositoryRepository;

/* Quartz scheduler dedicated to scheduled jobs using in memory data source */
Expand All @@ -45,7 +47,8 @@ public void init() throws ClassNotFoundException, SchedulerException {
// Attach Job and Trigger listeners on the 'scheduledJobs' scheduler
getScheduler()
.getListenerManager()
.addJobListener(new ScheduledJobListener(scheduledJobRepository));
.addJobListener(
new ScheduledJobListener(scheduledJobRepository, scheduledJobStatusRepository));
getScheduler()
.getListenerManager()
.addTriggerListener(new ScheduledJobTriggerListener(scheduledJobRepository));
Expand All @@ -65,15 +68,15 @@ public void init() throws ClassNotFoundException, SchedulerException {
}

// Clean up quartz jobs for this scheduler that are not in the DB.
cleanupDB();
// cleanupDB();
scheduleJobs();
}

public void cleanupDB() throws SchedulerException {
for (JobKey jobKey : getScheduler().getJobKeys(GroupMatcher.anyGroup())) {
if (scheduledJobRepository.findByJobKey(jobKey) == null) {
logger.info(
"Removing {} job for repo ID: {} as it's no longer the 'scheduled_job' table.",
"Removing {} job for repo ID: {} as it's no longer in the 'scheduled_job' table.",
jobKey.getGroup(),
jobKey.getName());
getScheduler().deleteJob(jobKey);
Expand All @@ -90,8 +93,11 @@ public void pushJobToDB(ThirdPartySyncJobConfig jobConfig) {
ScheduledJob scheduledJob = new ScheduledJob();
scheduledJob.setCron(jobConfig.getCron());
scheduledJob.setRepository(repositoryRepository.findByName(jobConfig.getRepository()));
scheduledJob.setJobStatus(ScheduledJobStatus.SCHEDULED);
scheduledJob.setJobType(ScheduledJobType.THIRD_PARTY_SYNC);
scheduledJob.setJobStatus(
scheduledJobStatusRepository.findByEnum(ScheduledJobStatus.IN_PROGRESS));

scheduledJob.setJobType(
scheduledJobTypeRepository.findByEnum(ScheduledJobType.THIRD_PARTY_SYNC));

ScheduledThirdPartySyncProperties thirdPartySyncProperties =
new ScheduledThirdPartySyncProperties();
Expand Down Expand Up @@ -124,19 +130,28 @@ public void scheduleJobs() throws ClassNotFoundException, SchedulerException {

// Retrieve job class from enum value e.g. THIRD_PARTY_SYNC -> ScheduledThirdPartySync
Class<? extends IScheduledJob> jobType =
loadJobClass(scheduledJob.getJobType().getJobClassName());
loadJobClass(scheduledJob.getJobType().getEnum().getJobClassName());

JobDetail job = JobBuilder.newJob(jobType).withIdentity(jobKey).build();

Trigger trigger = buildTrigger(jobKey, scheduledJob.getCron(), triggerKey);

if (!scheduledJob.getEnabled()) {
// The job is disabled and exists in Quartz, pause it
if (getScheduler().checkExists(jobKey)) {
getScheduler().pauseJob(jobKey);
}
return;
}

if (getScheduler().checkExists(jobKey)) {
getScheduler().rescheduleJob(triggerKey, trigger);
} else {
getScheduler().scheduleJob(job, trigger);
}

scheduledJob.setJobStatus(ScheduledJobStatus.SCHEDULED);
scheduledJob.setJobStatus(
scheduledJobStatusRepository.findByEnum(ScheduledJobStatus.SCHEDULED));
scheduledJobRepository.save(scheduledJob);
}
}
Expand All @@ -151,13 +166,14 @@ public Trigger buildTrigger(JobKey jobKey, String cronExpression, TriggerKey tri

private JobKey getJobKey(ScheduledJob scheduledJob) {
return new JobKey(
scheduledJob.getRepository().getId().toString(), scheduledJob.getJobType().toString());
scheduledJob.getRepository().getId().toString(),
scheduledJob.getJobType().getEnum().toString());
}

private TriggerKey getTriggerKey(ScheduledJob scheduledJob) {
return new TriggerKey(
"trigger_" + scheduledJob.getRepository().getId().toString(),
scheduledJob.getJobType().toString());
scheduledJob.getJobType().getEnum().toString());
}

public Scheduler getScheduler() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
package com.box.l10n.mojito.service.scheduledjob;

public interface ScheduledJobProperties {}
public abstract class ScheduledJobProperties {
private int version = 1;

public int getVersion() {
return version;
}

public void setVersion(int version) {
this.version = version;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public interface ScheduledJobRepository extends JpaRepository<ScheduledJob, Long

@Query(
"SELECT sj FROM ScheduledJob sj "
+ "WHERE sj.repository.id = :repositoryId AND sj.jobType = :jobType")
+ "WHERE sj.repository.id = :repositoryId AND sj.jobType.jobType = :jobType")
ScheduledJob findByRepositoryIdAndJobType(Long repositoryId, ScheduledJobType jobType);

default ScheduledJob findByJobKey(JobKey jobKey) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.box.l10n.mojito.service.scheduledjob;

import com.box.l10n.mojito.entity.ScheduledJobStatusEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface ScheduledJobStatusRepository
extends JpaRepository<ScheduledJobStatusEntity, Long> {
@Query("SELECT sjs FROM ScheduledJobStatusEntity sjs " + "WHERE sjs.jobStatus = :jobStatus")
ScheduledJobStatusEntity findByEnum(ScheduledJobStatus jobStatus);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.box.l10n.mojito.service.scheduledjob;

import com.box.l10n.mojito.entity.ScheduledJobTypeEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface ScheduledJobTypeRepository extends JpaRepository<ScheduledJobTypeEntity, Long> {
@Query("SELECT sjt FROM ScheduledJobTypeEntity sjt " + "WHERE sjt.jobType = :jobType")
ScheduledJobTypeEntity findByEnum(
com.box.l10n.mojito.service.scheduledjob.ScheduledJobType jobType);
}
Loading

0 comments on commit cc04046

Please sign in to comment.