package com.linkedin.thirdeye.anomaly.monitor;
import com.linkedin.thirdeye.client.DAORegistry;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.linkedin.thirdeye.anomaly.job.JobConstants.JobStatus;
import com.linkedin.thirdeye.anomaly.monitor.MonitorConstants.MonitorType;
import com.linkedin.thirdeye.anomaly.task.TaskConstants.TaskStatus;
import com.linkedin.thirdeye.anomaly.task.TaskContext;
import com.linkedin.thirdeye.anomaly.task.TaskInfo;
import com.linkedin.thirdeye.anomaly.task.TaskResult;
import com.linkedin.thirdeye.anomaly.task.TaskRunner;
import com.linkedin.thirdeye.datalayer.dto.JobDTO;
import com.linkedin.thirdeye.datalayer.dto.TaskDTO;
public class MonitorTaskRunner implements TaskRunner {
private static final Logger LOG = LoggerFactory.getLogger(MonitorJobRunner.class);
private DAORegistry DAO_REGISTRY = DAORegistry.getInstance();
@Override
public List<TaskResult> execute(TaskInfo taskInfo, TaskContext taskContext) throws Exception {
MonitorTaskInfo monitorTaskInfo = (MonitorTaskInfo) taskInfo;
MonitorType monitorType = monitorTaskInfo.getMonitorType();
if (monitorType.equals(MonitorType.UPDATE)) {
executeMonitorUpdate(monitorTaskInfo);
} else if (monitorType.equals(MonitorType.EXPIRE)) {
executeMonitorExpire(monitorTaskInfo);
} else {
throw new UnsupportedOperationException("Monitor task must be of type UPDATE/EXPIRE, found " + monitorType);
}
return null;
}
private void executeMonitorUpdate(MonitorTaskInfo monitorTaskInfo) {
LOG.info("Execute monitor udpate {}", monitorTaskInfo);
try {
// All jobs with status SCHEDULED
Set<Long> scheduledJobIds = findAllJobsWithStatusScheduled();
// All incomplete jobs with status SCHEDULED
Set<Long> incompleteScheduledJobIds = findIncompleteJobsWithStatusScheduled();
// All finished jobs with status SCHEDULED
scheduledJobIds.removeAll(incompleteScheduledJobIds);
if (!scheduledJobIds.isEmpty()) {
DAO_REGISTRY.getJobDAO().updateStatusAndJobEndTimeForJobIds(scheduledJobIds, JobStatus.COMPLETED, System.currentTimeMillis());
LOG.info("COMPLETED jobs {}", scheduledJobIds);
}
} catch (Exception e) {
LOG.error("Exception in monitor update task", e);
}
}
private void executeMonitorExpire(MonitorTaskInfo monitorTaskInfo) {
LOG.info("Execute monitor expire {}", monitorTaskInfo);
try {
int expireDaysAgo = monitorTaskInfo.getExpireDaysAgo();
// fist delete tasks then jobs, as task has a foreign key
int numAnomalyTasksDeleted = DAO_REGISTRY.getTaskDAO().deleteRecordsOlderThanDaysWithStatus(expireDaysAgo, TaskStatus.COMPLETED);
int numAnomalyJobsDeleted = DAO_REGISTRY.getJobDAO().deleteRecordsOlderThanDaysWithStatus(expireDaysAgo, JobStatus.COMPLETED);
// delete rows from detection status table, older than
int numDetectionStatusRowsDeleted = DAO_REGISTRY.getDetectionStatusDAO().deleteRecordsOlderThanDays(7);
LOG.info("Deleted {} anomaly jobs and {} anomaly tasks", numAnomalyJobsDeleted, numAnomalyTasksDeleted);
LOG.info("Deleted {} rows from detectionStatus table", numDetectionStatusRowsDeleted);
} catch (Exception e) {
LOG.error("Exception in monitor expire task", e);
}
}
private Set<Long> findAllJobsWithStatusScheduled() {
Set<Long> scheduledJobIds = new HashSet<>();
try {
List<JobDTO> scheduledJobs = DAO_REGISTRY.getJobDAO().findByStatus(JobStatus.SCHEDULED);
for (JobDTO job : scheduledJobs) {
scheduledJobIds.add(job.getId());
}
} catch (Exception e) {
LOG.error("Exception in finding jobs with status scheduled", e);
}
return scheduledJobIds;
}
private Set<Long> findIncompleteJobsWithStatusScheduled() {
Set<Long> incompleteScheduledJobIds = new HashSet<>();
List<TaskDTO> incompleteTasks = DAO_REGISTRY.getTaskDAO().findByStatusNotIn(TaskStatus.COMPLETED);
for (TaskDTO task : incompleteTasks) {
incompleteScheduledJobIds.add(task.getJobId());
}
return incompleteScheduledJobIds;
}
}