All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rapture.kernel.schedule.WorkflowExecsRepo Maven / Gradle / Ivy

The newest version!
/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2011-2016 Incapture Technologies LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package rapture.kernel.schedule;

import rapture.common.CallingContext;
import rapture.common.JobErrorAck;
import rapture.common.JobErrorAckStorage;
import rapture.common.JobErrorType;
import rapture.common.JobExecStatus;
import rapture.common.JobType;
import rapture.common.LastJobExecStorage;
import rapture.common.RaptureJob;
import rapture.common.RaptureJobExec;
import rapture.common.RaptureJobExecStorage;
import rapture.common.RaptureJobStorage;
import rapture.common.RaptureURI;
import rapture.common.Scheme;
import rapture.common.UpcomingJobExecStorage;
import rapture.common.WorkOrderExecutionState;
import rapture.common.WorkflowJobDetails;
import rapture.common.WorkflowJobExecDetails;
import rapture.common.dp.StepRecord;
import rapture.common.dp.WorkOrderDebug;
import rapture.common.dp.WorkerDebug;
import rapture.common.impl.jackson.JacksonUtil;
import rapture.common.impl.jackson.JsonContent;
import rapture.kernel.Kernel;
import rapture.kernel.dp.StepRecordUtil;
import rapture.repo.RepoVisitor;

import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

/**
 * @author bardhi
 * @since 3/9/15.
 */
public class WorkflowExecsRepo {

    private static final Logger log = Logger.getLogger(WorkflowExecsRepo.class);
    private static final long OLD_EXEC_THRESHOLD_DELTA = 10L * 24 * 3600 * 1000;
    private static final long OLD_ACK_THRESHOLD_DELTA = 24L * 3600 * 1000;

    public List getLastWorkflowJobExecs(final CallingContext context) {
        final List ret = new LinkedList();
        Long lateThreshold = createLateThreshold();

        LastJobExecStorage.visitAll(createRepoVisitor(context, ret, lateThreshold, false));
        return ret;
    }

    private RepoVisitor createRepoVisitor(final CallingContext context, final List execDetailsList, final Long lateThreshold,
            final Boolean isUpcoming) {
        return new RepoVisitor() {
            @Override
            public boolean visit(String name, JsonContent content, boolean isFolder) {
                if (!isFolder) {
                    RaptureJobExec exec = RaptureJobExecStorage.readFromJson(content);
                    if (exec.getJobType() == JobType.WORKFLOW) {
                        WorkflowJobExecDetails current = new WorkflowJobExecDetails();
                        current.setJobStatus(exec.getStatus());
                        String jobURI = exec.getJobURI();
                        current.setJobURI(jobURI);
                        Long execTime = exec.getExecTime();
                        current.setStartDate(execTime);
                        RaptureJob job = RaptureJobStorage.readByFields(jobURI);
                        if (job != null) {
                            current.setParameters(job.getParams());
                            current.setPassedParams(exec.getPassedParams());

                            String sc = job.getScriptURI();
                            String workflowURI = RaptureURI.createFromFullPath(new RaptureURI(sc, Scheme.WORKFLOW).getFullPath(), Scheme.WORKFLOW).toString();

                            current.setWorkflowURI(workflowURI);
                            current.setMaxRuntimeMinutes(job.getMaxRuntimeMinutes());
                            String additionalDetails = exec.getExecDetails();
                            if (additionalDetails != null && additionalDetails.length() > 0) {

                                WorkflowJobDetails workflowJobDetails = JacksonUtil.objectFromJson(additionalDetails, WorkflowJobDetails.class);
                                String workOrderURI = workflowJobDetails.getWorkOrderURI();

                                if (workOrderURI != null) {
                                    current.setWorkOrderURI(workOrderURI);
                                    int afterSlash = workOrderURI.lastIndexOf("/") + 1;
                                    if (workOrderURI.length() > afterSlash) {
                                        String workOrderID = workOrderURI.substring(afterSlash);
                                        current.setWorkOrderID(workOrderID);
                                    }
                                }

                                WorkOrderDebug workOrderDebug = Kernel.getDecision().getWorkOrderDebug(context, workOrderURI);
                                if (workOrderDebug != null) {
                                    WorkOrderExecutionState workOrderStatus = workOrderDebug.getOrder().getStatus();
                                    current.setWorkOrderStatus(workOrderStatus);
                                    Long lastUpdated = 0L;
                                    for (WorkerDebug workerDebug : workOrderDebug.getWorkerDebugs()) {
                                        for (StepRecord record : StepRecordUtil.getStepRecords(workerDebug.getWorker())) {
                                            Long endTime = record.getEndTime();
                                            if (endTime != null && endTime > lastUpdated) {
                                                lastUpdated = endTime;
                                            } else {
                                                Long startTime = record.getStartTime();
                                                if (startTime != null && startTime > lastUpdated) {
                                                    lastUpdated = startTime;
                                                }
                                            }
                                        }

                                    }
                                    current.setLastUpdated(lastUpdated);
                                    if (workOrderStatus == WorkOrderExecutionState.NEW || workOrderStatus == WorkOrderExecutionState.ACTIVE) {
                                        Long now = System.currentTimeMillis();
                                        if (job.getMaxRuntimeMinutes() != -1) {
                                            long totalMillis = now - execTime;
                                            long overrunMillis = totalMillis - job.getMaxRuntimeMinutes() * 60 * 1000;
                                            if (overrunMillis > 0) {
                                                current.setOverrunMillis(overrunMillis);
                                            }
                                        }
                                    }
                                }
                            }

                            WorkOrderExecutionState workOrderStatus = current.getWorkOrderStatus();
                            JobExecStatus jobStatus = current.getJobStatus();

                            if (isUpcoming) {
                                if (ExecStatusHelper.isLate(lateThreshold, current)) {
                                    current.setPrettyStatus("Late");
                                    current.setNotes(String.format("Should have started %s ago",
                                            ExecStatusHelper.prettyDuration(lateThreshold - current.getStartDate())));
                                    JobErrorAck errorAck = JobErrorAckStorage.readByFields(jobURI, execTime);
                                    current.setErrorAck(errorAck);
                                } else {
                                    current.setPrettyStatus("Not yet");
                                }
                            } else {
                                JobErrorAck errorAck = JobErrorAckStorage.readByFields(jobURI, execTime);
                                if (ExecStatusHelper.isSuccess(workOrderStatus, jobStatus)) {
                                    current.setPrettyStatus("Finished");
                                } else {
                                    current.setPrettyStatus("Running");
                                    if (ExecStatusHelper.isOk(workOrderStatus, jobStatus, current)) {
                                        current.setNotes("Still running");
                                    }
                                }
                                if (ExecStatusHelper.isFailed(workOrderStatus, jobStatus)) {
                                    if (workOrderStatus != null) {
                                        current.setPrettyStatus(workOrderStatus.toString());
                                    } else {
                                        current.setPrettyStatus("Failed to start");
                                    }
                                    if (errorAck != null && errorAck.getErrorType() == JobErrorType.FAILED) {
                                        current.setErrorAck(errorAck);
                                    }

                                } else if (ExecStatusHelper.isOverrun(current)) {
                                    current.setPrettyStatus(workOrderStatus.toString());
                                    String prettyOverrun = ExecStatusHelper.prettyDuration(current.getOverrunMillis());
                                    current.setNotes(String.format("Over by %s", prettyOverrun));

                                    if (errorAck != null && errorAck.getErrorType() == JobErrorType.OVERRUN) {
                                        current.setErrorAck(errorAck);
                                    }
                                }
                            }
                            JobErrorAck errorAck = current.getErrorAck();
                            if (errorAck != null && isExecOld(current) && isAckOld(errorAck)) {
                                if (log.isTraceEnabled()) {
                                    log.trace(String.format("Ignoring old acked exec, workflow=[%s], workorder=[%s], time=[%s]", current.getWorkflowURI(),
                                            current.getWorkOrderURI(), current.getStartDate()));
                                }
                            } else if (isOldDisabledOkJob(current, job)) {
                                if (log.isTraceEnabled()) {
                                    log.trace(String.format("Ignoring old OK workflow workflow=[%s], workorder=[%s], time=[%s]", current.getWorkflowURI(),
                                            current.getWorkOrderURI(), current.getStartDate()));
                                }
                            } else {
                                execDetailsList.add(current);
                            }
                        } else {
                            log.error(String.format("Unable to find job %s for execution %s ", jobURI, execTime));
                        }
                    }
                }
                return true;
            }

        };
    }

    /**
     * Returns true if an execution is old, the corresponding job is now disabled, and this execution suceeded
     *
     * @param exec
     * @param job
     * @return
     */
    private boolean isOldDisabledOkJob(WorkflowJobExecDetails exec, RaptureJob job) {
        boolean isOkAndNotLate =
                ExecStatusHelper.isOk(exec.getWorkOrderStatus(), exec.getJobStatus(), exec) && !ExecStatusHelper.isLate(createLateThreshold(), exec);

        boolean isSuccess = ExecStatusHelper.isSuccess(exec.getWorkOrderStatus(), exec.getJobStatus());
        boolean statusGreen = isOkAndNotLate || isSuccess;

        return !job.getActivated() && statusGreen && isExecOld(exec);
    }

    /**
     * Filter out execs execs that are too old
     *
     * @param execDetails
     * @return
     */
    private boolean isExecOld(WorkflowJobExecDetails execDetails) {
        Long timestamp;
        if (execDetails.getLastUpdated() != null) {
            timestamp = execDetails.getLastUpdated();
        } else {
            timestamp = execDetails.getStartDate();
        }
        long now = System.currentTimeMillis();
        Long earliestExecThreshold = now - OLD_EXEC_THRESHOLD_DELTA;
        return timestamp == null || timestamp < earliestExecThreshold;
    }

    /**
     * Filter out acks that are old
     *
     * @param errorAck
     * @return
     */
    private boolean isAckOld(JobErrorAck errorAck) {
        long now = System.currentTimeMillis();
        if (errorAck != null) {
            Long ackTime = errorAck.getTimestamp();
            Long earliestAckThreshold = now - OLD_ACK_THRESHOLD_DELTA;
            return ackTime == null || ackTime < earliestAckThreshold;
        } else {
            return true;
        }
    }

    public Long createLateThreshold() {
        // give the scheduler 1 minute leeway
        return System.currentTimeMillis() - 60 * 1000;
    }

    public List getUpcomingWorkflowJobExecs(final CallingContext context) {
        final List ret = new LinkedList();
        Long lateThreshold = createLateThreshold();

        UpcomingJobExecStorage.visitAll(createRepoVisitor(context, ret, lateThreshold, true));
        return ret;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy