org.opencron.server.service.ExecuteService.java Source code

Java tutorial

Introduction

Here is the source code for org.opencron.server.service.ExecuteService.java

Source

/**
 * Copyright 2016 benjobs
 * <p>
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.opencron.server.service;

import org.opencron.common.exception.PingException;
import org.opencron.common.job.Action;
import org.opencron.common.job.Request;
import org.opencron.common.job.Response;
import org.opencron.common.utils.ParamsMap;
import org.opencron.server.domain.Record;
import org.opencron.server.domain.Agent;
import org.opencron.server.domain.User;
import org.opencron.server.job.OpencronCaller;
import org.opencron.server.job.OpencronMonitor;
import org.opencron.server.vo.JobVo;
import com.mysql.jdbc.PacketTooBigException;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import static org.opencron.common.job.Opencron.*;

@Service
public class ExecuteService implements Job {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private RecordService recordService;

    @Autowired
    private JobService jobService;

    @Autowired
    private NoticeService noticeService;

    @Autowired
    private OpencronCaller opencronCaller;

    @Autowired
    private AgentService agentService;

    @Autowired
    private UserService userService;

    private Map<Long, Integer> reExecuteThreadMap = new HashMap<Long, Integer>(0);

    private static final String PACKETTOOBIG_ERROR = "?MySQL????,?max_allowed_packet";

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String key = jobExecutionContext.getJobDetail().getKey().getName();
        JobVo jobVo = (JobVo) jobExecutionContext.getJobDetail().getJobDataMap().get(key);
        try {
            ExecuteService executeService = (ExecuteService) jobExecutionContext.getJobDetail().getJobDataMap()
                    .get("jobBean");
            boolean success = executeService.executeJob(jobVo);
            this.loggerInfo("[opencron] job:{} at {}:{},execute:{}", jobVo, success ? "successful" : "failed");
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage(), e);
        }
    }

    /**
     * ?
     */
    public boolean executeJob(final JobVo job) {

        JobType jobType = JobType.getJobType(job.getJobType());
        switch (jobType) {
        case SINGLETON:
            return executeSingleJob(job, job.getUserId());//?
        case FLOW:
            return executeFlowJob(job);//?
        default:
            return false;
        }
    }

    /**
     * ?
     */
    private boolean executeSingleJob(JobVo job, Long userId) {

        if (!checkJobPermission(job.getAgentId(), userId))
            return false;

        Record record = new Record(job);
        record.setJobType(JobType.SINGLETON.getCode());//?
        try {
            //??
            record = recordService.save(record);
            //??
            checkPing(job, record);
            Response response = responseToRecord(job, record);
            recordService.save(record);
            if (!response.isSuccess()) {
                //?????.
                if (job.getRedo() == 0 || job.getRunCount() == 0) {
                    noticeService.notice(job, null);
                }
                this.loggerInfo("execute failed:jobName:{} at ip:{},port:{},info:{}", job, record.getMessage());
                return false;
            } else {
                this.loggerInfo("execute successful:jobName:{} at ip:{},port:{}", job, null);
            }
        } catch (PacketTooBigException e) {
            noticeService.notice(job, PACKETTOOBIG_ERROR);
            this.loggerError("execute failed:jobName:%s at ip:%s,port:%d,info:%s", job, PACKETTOOBIG_ERROR, e);
        } catch (Exception e) {
            if (job.getRedo() == 0 || job.getRunCount() == 0) {
                noticeService.notice(job, null);
            }
            this.loggerError("execute failed:jobName:%s at ip:%s,port:%d,info:%s", job, e.getMessage(), e);
        }
        return record.getSuccess().equals(ResultStatus.SUCCESSFUL.getStatus());
    }

    /**
     * ? ???
     */
    private boolean executeFlowJob(JobVo job) {
        if (!checkJobPermission(job.getAgentId(), job.getUserId()))
            return false;

        final long groupId = System.nanoTime() + Math.abs(new Random().nextInt());//??Id
        final Queue<JobVo> jobQueue = new LinkedBlockingQueue<JobVo>();
        jobQueue.add(job);
        jobQueue.addAll(job.getChildren());
        RunModel runModel = RunModel.getRunModel(job.getRunModel());
        switch (runModel) {
        case SEQUENCE:
            return executeSequenceJob(groupId, jobQueue);//
        case SAMETIME:
            return executeSameTimeJob(groupId, jobQueue);//
        default:
            return false;
        }
    }

    /**
     * ??
     */
    private boolean executeSequenceJob(long groupId, Queue<JobVo> jobQueue) {
        for (JobVo jobVo : jobQueue) {
            if (!doFlowJob(jobVo, groupId)) {
                return false;
            }
        }
        return true;
    }

    /**
     * ??
     */
    private boolean executeSameTimeJob(final long groupId, final Queue<JobVo> jobQueue) {
        final List<Boolean> result = new ArrayList<Boolean>(0);
        Thread jobThread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (final JobVo jobVo : jobQueue) {
                    //?(?,??)
                    Thread thread = new Thread(new Runnable() {
                        public void run() {
                            result.add(doFlowJob(jobVo, groupId));
                        }
                    });
                    thread.start();
                }
            }
        });
        jobThread.start();
        //?,?...
        try {
            jobThread.join();
        } catch (InterruptedException e) {
            logger.error("[opencron] job rumModel with SAMETIME error:{}", e.getMessage());
        }
        return !result.contains(false);
    }

    /**
     * ?
     */
    private boolean doFlowJob(JobVo job, long groupId) {
        Record record = new Record(job);
        record.setGroupId(groupId);//Id
        record.setJobType(JobType.FLOW.getCode());//?
        record.setFlowNum(job.getFlowNum());

        boolean success = true;

        try {
            //??
            record = recordService.save(record);
            //??
            checkPing(job, record);

            Response result = responseToRecord(job, record);

            if (!result.isSuccess()) {
                recordService.save(record);
                //kill,
                if (StatusCode.KILL.getValue().equals(result.getExitCode())) {
                    recordService.flowJobDone(record);
                } else {
                    success = false;
                }
                return false;
            } else {
                //???,?
                if (job.getLastChild()) {
                    recordService.save(record);
                    recordService.flowJobDone(record);
                } else {
                    //?????,??...
                    record.setStatus(RunStatus.RUNNING.getStatus());
                    recordService.save(record);
                }
                return true;
            }
        } catch (PingException e) {
            recordService.flowJobDone(record);//,?.
            return false;
        } catch (Exception e) {
            if (e instanceof PacketTooBigException) {
                record.setMessage(this.loggerError("execute failed(flow job):jobName:%s at ip:%s,port:%d,info:",
                        job, PACKETTOOBIG_ERROR, e));
            } else {
                record.setMessage(this.loggerError("execute failed(flow job):jobName:%s at ip:%s,port:%d,info:%s",
                        job, e.getMessage(), e));
            }
            record.setSuccess(ResultStatus.FAILED.getStatus());//?
            record.setReturnCode(StatusCode.ERROR_EXEC.getValue());
            record.setEndTime(new Date());
            recordService.save(record);
            success = false;
            return false;
        } finally {
            //???...
            if (!success) {
                Record red = recordService.get(record.getRecordId());
                if (job.getRedo() == 1 && job.getRunCount() > 0) {
                    int index = 0;
                    boolean flag;
                    do {
                        flag = reExecuteJob(red, job, JobType.FLOW);
                        ++index;
                    } while (!flag && index < job.getRunCount());

                    //?,??,?
                    if (!flag) {
                        noticeService.notice(job, null);
                        recordService.flowJobDone(record);
                    }
                } else {
                    noticeService.notice(job, null);
                    recordService.flowJobDone(record);
                }
            }
        }

    }

    /**
     * ? 
     */
    public void batchExecuteJob(final Long userId, String command, String agentIds) {
        final Queue<JobVo> jobQueue = new LinkedBlockingQueue<JobVo>();

        String[] arrayIds = agentIds.split(";");
        for (String agentId : arrayIds) {
            Agent agent = agentService.getAgent(Long.parseLong(agentId));
            JobVo jobVo = new JobVo(userId, command, agent);
            jobQueue.add(jobVo);
        }

        Thread jobThread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (final JobVo jobVo : jobQueue) {
                    //?(?,?)
                    Thread thread = new Thread(new Runnable() {
                        public void run() {
                            executeSingleJob(jobVo, userId);
                        }
                    });
                    thread.start();
                }
            }
        });
        jobThread.start();
    }

    /**
     * ?
     */
    public boolean reExecuteJob(final Record parentRecord, JobVo job, JobType jobType) {

        if (parentRecord.getRedoCount().equals(reExecuteThreadMap.get(parentRecord.getRecordId()))) {
            return false;
        } else {
            reExecuteThreadMap.put(parentRecord.getRecordId(), parentRecord.getRedoCount());
        }

        parentRecord.setStatus(RunStatus.RERUNNING.getStatus());
        Record record = new Record(job);

        try {
            recordService.save(parentRecord);
            /**
             * ??
             */
            job.setExecType(ExecType.RERUN.getStatus());
            record.setParentId(parentRecord.getRecordId());
            record.setGroupId(parentRecord.getGroupId());
            record.setJobType(jobType.getCode());
            parentRecord.setRedoCount(parentRecord.getRedoCount() + 1);//?
            record.setRedoCount(parentRecord.getRedoCount());
            record = recordService.save(record);

            //??
            checkPing(job, record);

            Response result = responseToRecord(job, record);

            //???,
            if (result.isSuccess()) {
                parentRecord.setStatus(RunStatus.RERUNDONE.getStatus());
                //???Kill,??
            } else if (StatusCode.KILL.getValue().equals(result.getExitCode())) {
                parentRecord.setStatus(RunStatus.RERUNDONE.getStatus());
            } else {
                //???,,?,??
                if (parentRecord.getRunCount().equals(parentRecord.getRedoCount())) {
                    noticeService.notice(job, null);
                }
                parentRecord.setStatus(RunStatus.RERUNUNDONE.getStatus());
            }
            this.loggerInfo("execute successful:jobName:{} at ip:{},port:{}", job, null);
        } catch (Exception e) {
            if (e instanceof PacketTooBigException) {
                noticeService.notice(job, PACKETTOOBIG_ERROR);
                errorExec(record, this.loggerError("execute failed:jobName:%s at ip:%s,port:%d,info:%s", job,
                        PACKETTOOBIG_ERROR, e));
            }
            noticeService.notice(job, e.getMessage());
            errorExec(record,
                    this.loggerError("execute failed:jobName:%s at ip:%s,port:%d,info:%s", job, e.getMessage(), e));

        } finally {
            //????
            if (parentRecord.getRunCount().equals(parentRecord.getRedoCount())) {
                parentRecord.setStatus(RunStatus.RERUNDONE.getStatus());
            }
            try {
                recordService.save(record);
                recordService.save(parentRecord);
            } catch (Exception e) {
                if (e instanceof PacketTooBigException) {
                    record.setMessage(this.loggerError(
                            "execute failed(flow job):jobName:%s at ip:%s,port:%d,info:" + PACKETTOOBIG_ERROR, job,
                            e.getMessage(), e));
                } else {
                    record.setMessage(
                            this.loggerError("execute failed(flow job):jobName:%s at ip:%s,port:%d,info:%s", job,
                                    e.getMessage(), e));
                }
            }

        }
        return record.getSuccess().equals(ResultStatus.SUCCESSFUL.getStatus());
    }

    /**
     * 
     */
    public boolean killJob(Record record) {

        final Queue<Record> recordQueue = new LinkedBlockingQueue<Record>();

        //?
        if (JobType.SINGLETON.getCode().equals(record.getJobType())) {
            recordQueue.add(record);
        } else if (JobType.FLOW.getCode().equals(record.getJobType())) {
            //?
            recordQueue.addAll(recordService.getRunningFlowJob(record.getRecordId()));
        }

        final List<Boolean> result = new ArrayList<Boolean>(0);
        Thread jobThread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (final Record cord : recordQueue) {
                    //kill(?,?kill)
                    Thread thread = new Thread(new Runnable() {
                        public void run() {
                            //??...
                            cord.setStatus(RunStatus.STOPPING.getStatus());//?
                            cord.setSuccess(ResultStatus.KILLED.getStatus());//?.
                            JobVo job = null;
                            try {
                                recordService.save(cord);
                                job = jobService.getJobVoById(cord.getJobId());
                                //???kill
                                opencronCaller.call(
                                        Request.request(job.getIp(), job.getPort(), Action.KILL, job.getPassword())
                                                .putParam("pid", cord.getPid()),
                                        job.getAgent());
                                cord.setStatus(RunStatus.STOPED.getStatus());
                                cord.setEndTime(new Date());
                                recordService.save(cord);
                                loggerInfo("killed successful :jobName:{} at ip:{},port:{},pid:{}", job,
                                        cord.getPid());
                            } catch (Exception e) {
                                if (e instanceof PacketTooBigException) {
                                    noticeService.notice(job, PACKETTOOBIG_ERROR);
                                    loggerError("killed error:jobName:%s at ip:%s,port:%d,pid:%s", job,
                                            cord.getPid() + " failed info: " + PACKETTOOBIG_ERROR, e);
                                }
                                noticeService.notice(job, null);
                                loggerError("killed error:jobName:%s at ip:%s,port:%d,pid:%s", job,
                                        cord.getPid() + " failed info: " + e.getMessage(), e);
                                result.add(false);
                            }
                        }
                    });
                    thread.start();
                }
            }
        });
        jobThread.start();

        //?kill,kill?...
        try {
            jobThread.join();
        } catch (InterruptedException e) {
            logger.error("[opencron] kill job with error:{}", e.getMessage());
        }
        return !result.contains(false);
    }

    /**
     * ?????
     */
    private Response responseToRecord(final JobVo job, final Record record) throws Exception {
        Response response = opencronCaller
                .call(Request.request(job.getIp(), job.getPort(), Action.EXECUTE, job.getPassword())
                        .putParam("command", job.getCommand()).putParam("pid", record.getPid())
                        .putParam("timeout", job.getTimeout() + ""), job.getAgent());
        logger.info("[opencron]:execute response:{}", response.toString());
        record.setReturnCode(response.getExitCode());
        record.setMessage(response.getMessage());

        record.setSuccess(
                response.isSuccess() ? ResultStatus.SUCCESSFUL.getStatus() : ResultStatus.FAILED.getStatus());
        if (StatusCode.KILL.getValue().equals(response.getExitCode())) {
            record.setStatus(RunStatus.STOPED.getStatus());
            record.setSuccess(ResultStatus.KILLED.getStatus());//kill
        } else if (StatusCode.TIME_OUT.getValue().equals(response.getExitCode())) {
            record.setStatus(RunStatus.STOPED.getStatus());
            record.setSuccess(ResultStatus.TIMEOUT.getStatus());//...
        } else {
            record.setStatus(RunStatus.DONE.getStatus());
        }

        record.setStartTime(new Date(response.getStartTime()));
        record.setEndTime(new Date(response.getEndTime()));
        return response;
    }

    /**
     * ??
     */
    private void errorExec(Record record, String errorInfo) {
        record.setSuccess(ResultStatus.FAILED.getStatus());//?
        record.setStatus(RunStatus.DONE.getStatus());//?
        record.setReturnCode(StatusCode.ERROR_EXEC.getValue());
        record.setEndTime(new Date());
        record.setMessage(errorInfo);
        recordService.save(record);
    }

    /**
     * ? 
     */
    private void checkPing(JobVo job, Record record) throws PingException {
        if (!ping(job.getAgent())) {
            record.setStatus(RunStatus.DONE.getStatus());//?
            record.setReturnCode(StatusCode.ERROR_PING.getValue());

            String format = "can't to communicate with agent:%s(%s:%d),execute job:%s failed";
            String content = String.format(format, job.getAgentName(), job.getIp(), job.getPort(),
                    job.getJobName());

            record.setMessage(content);
            record.setSuccess(ResultStatus.FAILED.getStatus());
            record.setEndTime(new Date());
            recordService.save(record);
            throw new PingException(content);
        }
    }

    public boolean ping(Agent agent) {
        boolean ping = false;
        try {
            ping = opencronCaller
                    .call(Request.request(agent.getIp(), agent.getPort(), Action.PING, agent.getPassword())
                            .putParam("serverPort", OpencronMonitor.port + ""), agent)
                    .isSuccess();
        } catch (Exception e) {
            logger.error("[opencron]ping failed,host:{},port:{}", agent.getIp(), agent.getPort());
        } finally {
            return ping;
        }
    }

    /**
     * ?
     */
    public boolean password(Agent agent, final String newPassword) {
        boolean ping = false;
        try {
            Response response = opencronCaller
                    .call(Request.request(agent.getIp(), agent.getPort(), Action.PASSWORD, agent.getPassword())
                            .putParam("newPassword", newPassword), agent);
            ping = response.isSuccess();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ping;
    }

    /**
     * ??
     */
    public Response monitor(Agent agent) throws Exception {
        return opencronCaller.call(
                Request.request(agent.getIp(), agent.getPort(), Action.MONITOR, agent.getPassword()).setParams(
                        ParamsMap.instance().fill("connType", ConnType.getByType(agent.getProxy()).getName())),
                agent);
    }

    /**
     * ??
     */
    private boolean checkJobPermission(Long jobAgentId, Long userId) {
        if (userId == null)
            return false;
        User user = userService.getUserById(userId);
        //???
        if (user != null && user.getRoleId() == 999)
            return true;
        String agentIds = userService.getUserById(userId).getAgentIds();
        agentIds = "," + agentIds + ",";
        String thisAgentId = "," + jobAgentId + ",";
        return agentIds.contains(thisAgentId);
    }

    private void loggerInfo(String str, JobVo job, String message) {
        if (message != null) {
            logger.info(str, job.getJobName(), job.getIp(), job.getPort(), message);
        } else {
            logger.info(str, job.getJobName(), job.getIp(), job.getPort());
        }
    }

    private String loggerError(String str, JobVo job, String message, Exception e) {
        String errorInfo = String.format(str, job.getJobName(), job.getIp(), job.getPort(), message);
        logger.error(errorInfo, e);
        return errorInfo;
    }
}