Package org.qzerver.model.service.job.execution.impl

Source Code of org.qzerver.model.service.job.execution.impl.ScheduleExecutionManagementServiceImpl

package org.qzerver.model.service.job.execution.impl;

import com.gainmatrix.lib.business.entity.BusinessEntityDao;
import com.gainmatrix.lib.business.exception.AbstractServiceException;
import com.gainmatrix.lib.business.exception.MissingEntityException;
import com.gainmatrix.lib.paging.Extraction;
import com.gainmatrix.lib.spring.validation.BeanValidationUtils;
import com.gainmatrix.lib.time.Chronometer;
import com.google.common.base.Preconditions;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Hibernate;
import org.qzerver.model.dao.job.ScheduleExecutionDao;
import org.qzerver.model.domain.entities.cluster.ClusterGroup;
import org.qzerver.model.domain.entities.cluster.ClusterNode;
import org.qzerver.model.domain.entities.job.ScheduleAction;
import org.qzerver.model.domain.entities.job.ScheduleExecution;
import org.qzerver.model.domain.entities.job.ScheduleExecutionNode;
import org.qzerver.model.domain.entities.job.ScheduleExecutionResult;
import org.qzerver.model.domain.entities.job.ScheduleExecutionStatus;
import org.qzerver.model.domain.entities.job.ScheduleJob;
import org.qzerver.model.service.cluster.ClusterManagementService;
import org.qzerver.model.service.job.execution.ScheduleExecutionManagementService;
import org.qzerver.model.service.job.execution.dto.StartExecutionParameters;
import org.qzerver.model.service.job.execution.exception.ExecutionAlreadyFinishedException;
import org.qzerver.model.service.job.execution.exception.ResultAlreadyFinishedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.Validator;

import javax.validation.constraints.NotNull;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

@Transactional(propagation = Propagation.REQUIRED)
public class ScheduleExecutionManagementServiceImpl implements ScheduleExecutionManagementService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleExecutionManagementServiceImpl.class);

    @NotNull
    private ScheduleExecutionDao scheduleExecutionDao;

    @NotNull
    private Chronometer chronometer;

    @NotNull
    private ClusterManagementService clusterManagementService;

    @NotNull
    private BusinessEntityDao businessEntityDao;

    @NotNull
    private String node;

    @NotNull
    private Validator beanValidator;

    @Override
    public ScheduleExecution startExecution(long scheduleJobId, StartExecutionParameters parameters) {
        BeanValidationUtils.checkValidity(parameters, beanValidator);

        LOGGER.debug("Start execution of job [id={}]", scheduleJobId);

        Date now = chronometer.getCurrentMoment();

        // Select job by id
        ScheduleJob scheduleJob = businessEntityDao.lockById(ScheduleJob.class, scheduleJobId);
        if (scheduleJob == null) {
            throw new MissingEntityException(ScheduleJob.class, scheduleJobId);
        }

        // Action
        ScheduleAction scheduleAction = scheduleJob.getAction();
        scheduleAction.setUsedDate(now);
        scheduleAction.incrementUsedCount();

        // Create new execution
        ScheduleExecution scheduleExecution = new ScheduleExecution();
        scheduleExecution.setJob(scheduleJob);
        scheduleExecution.setAction(scheduleAction);
        scheduleExecution.setCron(scheduleJob.getCron());
        scheduleExecution.setName(scheduleJob.getName());
        scheduleExecution.setStrategy(scheduleJob.getStrategy());
        scheduleExecution.setTimeout(scheduleJob.getTimeout());
        scheduleExecution.setAllNodes(scheduleJob.isAllNodes());
        scheduleExecution.setAllNodesPool(scheduleJob.getAllNodesPool());
        scheduleExecution.setScheduled(parameters.getScheduled());
        scheduleExecution.setFired(parameters.getFired());
        scheduleExecution.setForced(parameters.isManual());
        scheduleExecution.setDescription(parameters.getComment());
        scheduleExecution.setStatus(ScheduleExecutionStatus.INPROGRESS);
        scheduleExecution.setStarted(now);
        scheduleExecution.setFinished(null);

        String hostName = StringUtils.left(node, ScheduleExecution.MAX_NODE_LENGTH);
        scheduleExecution.setHostname(hostName);

        List<ScheduleExecutionNode> nodes = selectExecutionNodes(scheduleJob, parameters);
        for (ScheduleExecutionNode node : nodes) {
            node.setExecution(scheduleExecution);
            scheduleExecution.getNodes().add(node);
        }

        businessEntityDao.save(scheduleExecution);

        return scheduleExecution;
    }

    private List<ScheduleExecutionNode> selectExecutionNodes(ScheduleJob scheduleJob,
        StartExecutionParameters parameters)
    {
        // If specific address list is set then use it
        if (CollectionUtils.isNotEmpty(parameters.getAddresses())) {
            List<String> addresses = parameters.getAddresses();
            List<ScheduleExecutionNode> result = new ArrayList<ScheduleExecutionNode>(addresses.size());
            for (int i = 0, size = addresses.size(); i < size; i++) {
                String address = parameters.getAddresses().get(i);
                ScheduleExecutionNode executionNode = new ScheduleExecutionNode();
                executionNode.setOrderIndex(i);
                executionNode.setLocalhost(false);
                executionNode.setAddress(address);
                result.add(executionNode);
            }
            return result;
        }

        // If cluster is set then choose some nodes to work on
        ClusterGroup clusterGroup = scheduleJob.getCluster();
        if (clusterGroup != null) {
            List<ClusterNode> selectedNodes = selectClusterNodes(scheduleJob);
            List<ScheduleExecutionNode> result = new ArrayList<ScheduleExecutionNode>(selectedNodes.size());
            for (int i = 0, size = selectedNodes.size(); i < size; i++) {
                ClusterNode clusterNode = selectedNodes.get(i);
                ScheduleExecutionNode executionNode = new ScheduleExecutionNode();
                executionNode.setOrderIndex(i);
                executionNode.setLocalhost(false);
                executionNode.setAddress(clusterNode.getAddress());
                result.add(executionNode);
            }
            return result;
        }

        // If cluster is not set then the only node is 'localhost' node
        ScheduleExecutionNode executionNode = new ScheduleExecutionNode();
        executionNode.setOrderIndex(0);
        executionNode.setLocalhost(true);
        executionNode.setAddress("localhost");
        return Collections.singletonList(executionNode);
    }

    private List<ClusterNode> selectClusterNodes(ScheduleJob scheduleJob) {
        ClusterGroup clusterGroup = scheduleJob.getCluster();

        List<ClusterNode> selectedNodes;

        // Choose nodes depending on the selection strategy
        switch (scheduleJob.getStrategy()) {
            case INDEXED:
                selectedNodes = selectClusterNodesInIndexedOrder(clusterGroup);
                break;
            case RANDOM:
                selectedNodes = selectClusterNodesInRandomOrder(clusterGroup);
                break;
            case CIRCULAR:
                selectedNodes = selectClusterNodesInCircularOrder(clusterGroup);
                break;
            default:
                throw new IllegalStateException("Unknown strategy: " + scheduleJob.getStrategy());
        }

        // Limit node count if trial count is set
        if ((scheduleJob.getNodesLimit() > 0) && (scheduleJob.getNodesLimit() < selectedNodes.size())) {
            selectedNodes = selectedNodes.subList(0, scheduleJob.getNodesLimit());
        }

        return selectedNodes;
    }

    private List<ClusterNode> selectClusterNodesInIndexedOrder(ClusterGroup clusterGroup) {
        List<ClusterNode> selectedNodes = new ArrayList<ClusterNode>(clusterGroup.getNodes().size());

        // "line" strategy - always start from the first active node
        for (ClusterNode clusterNode : clusterGroup.getNodes()) {
            if (clusterNode.isEnabled()) {
                selectedNodes.add(clusterNode);
            }
        }

        return selectedNodes;
    }

    private List<ClusterNode> selectClusterNodesInRandomOrder(ClusterGroup clusterGroup) {
        List<ClusterNode> selectedNodes = new ArrayList<ClusterNode>(clusterGroup.getNodes().size());

        // "random" strategy - choose active nodes in random order
        for (ClusterNode clusterNode : clusterGroup.getNodes()) {
            if (clusterNode.isEnabled()) {
                selectedNodes.add(clusterNode);
            }
        }

        Collections.shuffle(selectedNodes);

        return selectedNodes;
    }

    private List<ClusterNode> selectClusterNodesInCircularOrder(ClusterGroup clusterGroup) {
        List<ClusterNode> selectedNodes = new ArrayList<ClusterNode>(clusterGroup.getNodes().size());

        // "circle" strategy - step index in cluster and get all active nodes
        int rolledIndex = clusterManagementService.rollGroupIndex(clusterGroup.getId());

        for (int i = rolledIndex, size = clusterGroup.getNodes().size(); i < size; i++) {
            ClusterNode clusterNode = clusterGroup.getNodes().get(i);
            if (clusterNode.isEnabled()) {
                selectedNodes.add(clusterNode);
            }
        }

        for (int i = 0; i < rolledIndex; i++) {
            ClusterNode clusterNode = clusterGroup.getNodes().get(i);
            if (clusterNode.isEnabled()) {
                selectedNodes.add(clusterNode);
            }
        }

        return selectedNodes;
    }

    @Override
    public ScheduleExecutionResult startExecutionResult(long scheduleExecutionNodeId) throws AbstractServiceException {
        ScheduleExecutionNode node = businessEntityDao.findById(ScheduleExecutionNode.class, scheduleExecutionNodeId);
        if (node == null) {
            throw new MissingEntityException(ScheduleExecutionNode.class, scheduleExecutionNodeId);
        }

        ScheduleExecution scheduleExecution = node.getExecution();

        if (scheduleExecution.getFinished() != null) {
            throw new ExecutionAlreadyFinishedException(scheduleExecution.getId());
        }

        businessEntityDao.lock(scheduleExecution);

        ScheduleExecutionResult result = new ScheduleExecutionResult();
        result.setOrderIndex(node.getOrderIndex());
        result.setStarted(chronometer.getCurrentMoment());
        result.setFinished(null);
        result.setSucceed(false);

        result.setNode(node);
        node.setResult(result);

        result.setExecution(scheduleExecution);
        scheduleExecution.getResults().add(result);

        businessEntityDao.save(result);

        return result;
    }

    @Override
    public ScheduleExecutionResult finishExecutionResult(long scheduleExecutionResultId, boolean succeed, byte[] data)
        throws AbstractServiceException
    {
        ScheduleExecutionResult result =
            businessEntityDao.findById(ScheduleExecutionResult.class, scheduleExecutionResultId);

        if (result == null) {
            throw new MissingEntityException(ScheduleExecutionResult.class, scheduleExecutionResultId);
        }

        if (result.getFinished() != null) {
            throw new ResultAlreadyFinishedException(result.getId());
        }

        result.setFinished(chronometer.getCurrentMoment());
        result.setSucceed(succeed);
        result.setPayload(data);

        return result;
    }

    @Override
    public ScheduleExecution finishExecution(long scheduleExecutionId, ScheduleExecutionStatus status)
        throws AbstractServiceException
    {
        Preconditions.checkNotNull(status);

        ScheduleExecution scheduleExecution = businessEntityDao.lockById(ScheduleExecution.class, scheduleExecutionId);
        if (scheduleExecution == null) {
            throw new MissingEntityException(ScheduleExecution.class, scheduleExecutionId);
        }

        if (scheduleExecution.getFinished() != null) {
            throw new ExecutionAlreadyFinishedException(scheduleExecution.getId());
        }

        scheduleExecution.setFinished(chronometer.getCurrentMoment());
        scheduleExecution.setStatus(status);
        scheduleExecution.setCancelled(false);

        Hibernate.initialize(scheduleExecution.getResults());
        Hibernate.initialize(scheduleExecution.getNodes());
        Hibernate.initialize(scheduleExecution.getJob());
        Hibernate.initialize(scheduleExecution.getAction());

        return scheduleExecution;
    }

    @Override
    @Transactional(readOnly = true)
    public ScheduleExecution findExecution(long scheduleExecutionId) {
        ScheduleExecution scheduleExecution = businessEntityDao.findById(ScheduleExecution.class, scheduleExecutionId);

        Hibernate.initialize(scheduleExecution.getResults());
        Hibernate.initialize(scheduleExecution.getNodes());
        Hibernate.initialize(scheduleExecution.getAction());

        return scheduleExecution;
    }

    @Override
    public ScheduleExecution cancelExecution(long scheduleExecutionId) throws AbstractServiceException {
        ScheduleExecution scheduleExecution = businessEntityDao.lockById(ScheduleExecution.class, scheduleExecutionId);
        if (scheduleExecution == null) {
            throw new MissingEntityException(ScheduleExecution.class, scheduleExecutionId);
        }

        if (scheduleExecution.getFinished() != null) {
            throw new ExecutionAlreadyFinishedException(scheduleExecutionId);
        }

        scheduleExecution.setCancelled(true);

        return scheduleExecution;
    }

    @Override
    public List<ScheduleExecution> findAll(Extraction extraction) {
        return scheduleExecutionDao.findAll(extraction);
    }

    @Override
    public List<ScheduleExecution> findByJob(long scheduleJobId, Extraction extraction) {
        return scheduleExecutionDao.findByJob(scheduleJobId, extraction);
    }

    @Override
    public List<ScheduleExecution> findEngaged(Extraction extraction) {
        return scheduleExecutionDao.findEngaged(extraction);
    }

    @Override
    public List<ScheduleExecution> findFinished(Extraction extraction) {
        return scheduleExecutionDao.findFinished(extraction);
    }

    @Required
    public void setScheduleExecutionDao(ScheduleExecutionDao scheduleExecutionDao) {
        this.scheduleExecutionDao = scheduleExecutionDao;
    }

    @Required
    public void setChronometer(Chronometer chronometer) {
        this.chronometer = chronometer;
    }

    @Required
    public void setClusterManagementService(ClusterManagementService clusterManagementService) {
        this.clusterManagementService = clusterManagementService;
    }

    @Required
    public void setNode(String node) {
        this.node = node;
    }

    @Required
    public void setBusinessEntityDao(BusinessEntityDao businessEntityDao) {
        this.businessEntityDao = businessEntityDao;
    }

    @Required
    public void setBeanValidator(Validator beanValidator) {
        this.beanValidator = beanValidator;
    }
}
TOP

Related Classes of org.qzerver.model.service.job.execution.impl.ScheduleExecutionManagementServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.