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

com.alibaba.schedulerx.service.JobSyncPopService Maven / Gradle / Ivy

There is a newer version: 1.12.2
Show newest version
package com.alibaba.schedulerx.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.schedulerx.JobProperty;
import com.alibaba.schedulerx.SchedulerxProperties;
import com.alibaba.schedulerx.common.domain.ContactInfo;
import com.alibaba.schedulerx.common.domain.JobType;
import com.alibaba.schedulerx.common.domain.TimeType;
import com.alibaba.schedulerx.common.sdk.common.MonitorConfig;
import com.alibaba.schedulerx.common.util.CronExpression;
import com.alibaba.schedulerx.common.util.JsonUtil;
import com.alibaba.schedulerx.common.util.StringUtils;
import com.alibaba.schedulerx.worker.log.LogFactory;
import com.alibaba.schedulerx.worker.log.Logger;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.InstanceProfileCredentialsProvider;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.schedulerx2.model.v20190430.CreateAppGroupRequest;
import com.aliyuncs.schedulerx2.model.v20190430.CreateAppGroupResponse;
import com.aliyuncs.schedulerx2.model.v20190430.CreateJobRequest;
import com.aliyuncs.schedulerx2.model.v20190430.CreateJobResponse;
import com.aliyuncs.schedulerx2.model.v20190430.CreateNamespaceRequest;
import com.aliyuncs.schedulerx2.model.v20190430.CreateNamespaceResponse;
import com.aliyuncs.schedulerx2.model.v20190430.GetJobInfoRequest;
import com.aliyuncs.schedulerx2.model.v20190430.GetJobInfoResponse;
import com.aliyuncs.schedulerx2.model.v20190430.GetJobInfoResponse.Data.JobConfigInfo;
import com.aliyuncs.schedulerx2.model.v20190430.UpdateJobRequest;
import com.aliyuncs.schedulerx2.model.v20190430.UpdateJobResponse;

/**
 * @author xiaomeng.hxm
 *
 */
public class JobSyncPopService implements JobSyncService {
    
    private static final Logger LOGGER = LogFactory.getLogger(JobSyncPopService.class);
    
    private static final String NAMESPACE_SOURCE_SPRINGBOOT = "springboot";
    
    @Autowired
    private SchedulerxProperties properties;

    private DefaultAcsClient client;

    /**
     * getClient
     * @return
     */
    private synchronized DefaultAcsClient getClient() {
        //构建 OpenApi 客户端
        if (client == null) {
            DefaultProfile.addEndpoint(properties.getRegionId(), "schedulerx2", "schedulerx.aliyuncs.com");
            if (StringUtils.isNotEmpty(properties.getAliyunRamRole())) {
                DefaultProfile profile = DefaultProfile.getProfile(properties.getRegionId());
                InstanceProfileCredentialsProvider provider = new InstanceProfileCredentialsProvider(
                        properties.getAliyunRamRole());
                client = new DefaultAcsClient(profile, provider);
            } else {
                DefaultProfile defaultProfile = DefaultProfile.getProfile(properties.getRegionId(),
                        properties.getAliyunAccessKey(),
                        properties.getAliyunSecretKey());
                client = new DefaultAcsClient(defaultProfile);
            }
        }
        return client;
    }

    /**
     * 同步指定任务配置信息
     * @param jobs
     * @throws Exception
     */
    @Override
    public synchronized void syncJobs(Map jobs, String namespaceSource) throws Exception {
        DefaultAcsClient client = getClient();
        for (Entry entry : jobs.entrySet()) {
            String jobName = entry.getKey();
            JobProperty jobProperty = entry.getValue();
            JobConfigInfo jobConfigInfo = getJob(client, jobName, namespaceSource);
            if (jobConfigInfo == null) {
                createJob(client, jobName, jobProperty, namespaceSource);
            } else if (jobProperty.isOverwrite()) {
                updateJob(client, jobConfigInfo, jobProperty, namespaceSource);
            }
        }
    }
    
    @Override
    public void syncJobs() throws Exception {
        // 1. 同步命名空间
        if (syncNamespace(getClient())){
            // 2. 同步应用分组
            if(syncAppGroup(getClient())){
                syncJobs(properties.getJobs(), getNamespaceSource());
                properties.setNamespaceSource(getNamespaceSource());
            }
        }
    }
    
    @Override
    public boolean syncNamespace(DefaultAcsClient client) throws Exception {
        if (StringUtils.isEmpty(properties.getNamespace())) {
            LOGGER.error("please set spring.schedulerx2.namespace");
            throw new IOException("please set spring.schedulerx2.namespace");
        }
        
        if (StringUtils.isEmpty(properties.getNamespaceName())) {
            LOGGER.error("please set spring.schedulerx2.namespaceName");
            throw new IOException("please set spring.schedulerx2.namespaceName");
        }
        
        CreateNamespaceRequest request = new CreateNamespaceRequest();
        request.setUid(properties.getNamespace());
        request.setName(properties.getNamespaceName());
        request.setSource(getNamespaceSource());
        CreateNamespaceResponse response = client.getAcsResponse(request);
        if (response.getSuccess()) {
            LOGGER.info(JsonUtil.toJson(response));
            return true;
        } else {
            throw new IOException(response.getMessage());
        }
        
    }
    
    /**
     * 
     * @param client
     * @return true if create new appGroup
     * @throws Exception
     */
    @Override
    public boolean syncAppGroup(DefaultAcsClient client) throws Exception {
        if (StringUtils.isEmpty(properties.getAppName())) {
            LOGGER.error("please set spring.schedulerx2.appName");
            throw new IOException("please set spring.schedulerx2.appName");
        }
        
        if (StringUtils.isEmpty(properties.getAppKey())) {
            LOGGER.error("please set spring.schedulerx2.appKey");
            throw new IOException("please set spring.schedulerx2.appKey");
        }
        
        if (StringUtils.isEmpty(properties.getGroupId())) {
            LOGGER.error("please set spring.schedulerx2.groupId");
            throw new IOException("please set spring.schedulerx2.groupId");
        }
        
        CreateAppGroupRequest request = new CreateAppGroupRequest();
        request.setNamespace(properties.getNamespace());
        request.setNamespaceSource(getNamespaceSource());
        request.setAppName(properties.getAppName());
        request.setGroupId(properties.getGroupId());
        request.setAppKey(properties.getAppKey());
        if (StringUtils.isNotEmpty(properties.getAlarmChannel())) {
            MonitorConfig monitorConfig = new MonitorConfig();
            monitorConfig.setSendChannel(properties.getAlarmChannel());
            request.setMonitorConfigJson(JsonUtil.toJson(monitorConfig));
        }
        if (!properties.getAlarmUsers().isEmpty()) {
            List contactInfos = new ArrayList(properties.getAlarmUsers().values());
            request.setMonitorContactsJson(JsonUtil.toJson(contactInfos));
        }
        CreateAppGroupResponse response = client.getAcsResponse(request);
        if (response.getSuccess()) {
            LOGGER.info(JsonUtil.toJson(response));
            return true;
        } else {
            throw new IOException(response.getMessage());
        }
    }
    
    private JobConfigInfo getJob(DefaultAcsClient client, String jobName, String namespaceSource) throws Exception {
        GetJobInfoRequest request = new GetJobInfoRequest();
        request.setNamespace(properties.getNamespace());
        request.setNamespaceSource(namespaceSource);
        request.setGroupId(properties.getGroupId());
        request.setJobId(0L);
        request.setJobName(jobName);
        GetJobInfoResponse response = client.getAcsResponse(request);
        if (response.getSuccess()) {
            return response.getData().getJobConfigInfo();
        }
        return null;
    }
    
    private void createJob(DefaultAcsClient client, String jobName, JobProperty jobProperty, String namespaceSource) throws Exception {
        CreateJobRequest request = new CreateJobRequest();
        request.setNamespace(properties.getNamespace());
        request.setNamespaceSource(namespaceSource);
        request.setGroupId(properties.getGroupId());
        request.setName(jobName);
        request.setParameters(jobProperty.getJobParameter());
        
        //java任务
        if (jobProperty.getJobType().equals(JobType.JAVA.getKey())) {
            request.setJobType("java");
            request.setClassName(jobProperty.getClassName());
        } else {
            request.setJobType(jobProperty.getJobType());
        }
        
        if (jobProperty.getJobModel().equals("mapreduce")) {
            request.setExecuteMode("batch");
        } else {
            request.setExecuteMode(jobProperty.getJobModel());
        }
        if (StringUtils.isNotEmpty(jobProperty.getDescription())) {
            request.setDescription(jobProperty.getDescription());
        }

        if (StringUtils.isNotEmpty(jobProperty.getContent())) {
            request.setContent(jobProperty.getContent());
        }
        
        if (StringUtils.isNotEmpty(jobProperty.getCron()) && StringUtils.isNotEmpty(jobProperty.getOneTime())) {
            throw new IOException("cron and oneTime shouldn't set together");
        }
        if (StringUtils.isNotEmpty(jobProperty.getCron())) {            
            //计算两次调度之间的频率,小于60秒是秒级别
            CronExpression cronExpression = new CronExpression(jobProperty.getCron());
            Date now = new Date();
            Date nextData = cronExpression.getTimeAfter(now);
            Date next2Data = cronExpression.getTimeAfter(nextData);
            if(nextData != null && next2Data != null) {
                long interval = (next2Data.getTime() - nextData.getTime()) / 1000;
                if (interval < 60) {
                    request.setTimeType(TimeType.SECOND_DELAY.getValue());
                    request.setTimeExpression(String.valueOf(interval<1?1:interval));
                }else {
                    request.setTimeType(TimeType.CRON.getValue());
                    request.setTimeExpression(jobProperty.getCron());
                }
            }else {
                request.setTimeType(TimeType.CRON.getValue());
                request.setTimeExpression(jobProperty.getCron());
            }
        } else if (StringUtils.isNotEmpty(jobProperty.getOneTime())) {
            request.setTimeType(TimeType.ONE_TIME.getValue());
            request.setTimeExpression(jobProperty.getOneTime());
        } else {
            request.setTimeType(TimeType.API.getValue());
        }

        if (jobProperty.getTimeType() != null) {
            request.setTimeType(jobProperty.getTimeType());
            if (StringUtils.isNotEmpty(jobProperty.getTimeExpression())) {
                request.setTimeExpression(jobProperty.getTimeExpression());
            }
        }
        
        // 监控报警
        request.setTimeoutEnable(true);
        request.setTimeoutKillEnable(true);
        request.setSendChannel("default");
        request.setFailEnable(true);
        request.setTimeout(3600L);
        // 高级配置,配置失败自动重试
        request.setMaxAttempt(3);
        request.setAttemptInterval(30);
        CreateJobResponse response = client.getAcsResponse(request);
        if (response.getSuccess()) {
            LOGGER.info("create schedulerx job successfully, jobId={}, jobName={}", response.getData().getJobId(), jobName);
        } else {
            throw new IOException("create schedulerx job failed, jobName=" + jobName + ", message=" + response.getMessage());
        }
    }
    
    private void updateJob(DefaultAcsClient client, JobConfigInfo jobConfigInfo, JobProperty jobProperty, String namespaceSource) throws Exception {
        String executeMode = jobProperty.getJobModel();
        if (jobProperty.getJobModel().equals("mapreduce")) {
            executeMode = "batch";
        }
        int timeType = TimeType.CRON.getValue();
        String timeExpression = null;
        if (StringUtils.isNotEmpty(jobProperty.getCron()) && StringUtils.isNotEmpty(jobProperty.getOneTime())) {
            throw new IOException("cron and oneTime shouldn't set together");
        }
        if (StringUtils.isNotEmpty(jobProperty.getCron())) {            
            //计算两次调度之间的频率,小于60秒是秒级别
            CronExpression cronExpression = new CronExpression(jobProperty.getCron());
            Date now = new Date();
            Date nextData = cronExpression.getTimeAfter(now);
            Date next2Data = cronExpression.getTimeAfter(nextData);
            if(nextData != null && next2Data != null) {
                long interval = (next2Data.getTime() - nextData.getTime()) / 1000;
                if (interval < 60) {
                    timeType = TimeType.SECOND_DELAY.getValue();
                    timeExpression = String.valueOf(interval<1?1:interval);
                }else {
                    timeType = TimeType.CRON.getValue();
                    timeExpression = jobProperty.getCron();
                }
            }else {
                timeType = TimeType.CRON.getValue();
                timeExpression = jobProperty.getCron();
            }
        } else if (StringUtils.isNotEmpty(jobProperty.getOneTime())) {
            timeType = TimeType.ONE_TIME.getValue();
            timeExpression = jobProperty.getOneTime();
        } else {
            timeType = TimeType.API.getValue();
        }
        
        boolean needUpdate = false;
        if (!jobConfigInfo.getDescription().equals(jobProperty.getDescription())
            || !jobConfigInfo.getClassName().equals(jobProperty.getClassName())
            || !jobConfigInfo.getParameters().equals(jobProperty.getJobParameter())
            || !jobConfigInfo.getExecuteMode().equals(executeMode)
            || jobConfigInfo.getTimeConfig().getTimeType() != timeType
            || !jobConfigInfo.getTimeConfig().getTimeExpression().equals(timeExpression)) {
            needUpdate = true;
            
            UpdateJobRequest request = new UpdateJobRequest();
            request.setNamespace(properties.getNamespace());
            request.setNamespaceSource(namespaceSource);
            request.setGroupId(properties.getGroupId());
            request.setJobId(jobConfigInfo.getJobId());
            request.setName(jobConfigInfo.getName());
            request.setParameters(jobProperty.getJobParameter());
            
            //java任务
            if (jobProperty.getJobType().equals(JobType.JAVA.getKey())) {
                request.setClassName(jobProperty.getClassName());
            }
            request.setExecuteMode(executeMode);
            if (StringUtils.isNotEmpty(jobProperty.getDescription())) {
                request.setDescription(jobProperty.getDescription());
            }
            request.setTimeType(timeType);
            request.setTimeExpression(timeExpression);
            
            // 监控报警
            request.setTimeoutEnable(true);
            request.setTimeoutKillEnable(true);
            request.setSendChannel("default");
            request.setFailEnable(true);
            request.setTimeout(3600L);
            // 高级配置,配置失败自动重试
            request.setMaxAttempt(3);
            request.setAttemptInterval(30);
            
            UpdateJobResponse response = client.getAcsResponse(request);
            if (response.getSuccess()) {
                LOGGER.info("update schedulerx job successfully, jobId={}, jobName={}", jobConfigInfo.getJobId(), jobConfigInfo.getName());
            } else {
                throw new IOException("update schedulerx job failed, jobName=" + jobConfigInfo.getName() + ", message=" + response.getMessage());
            }
        }
    }

    /**
     * 获取声明式命名空间来源
     * @return
     */
    private String getNamespaceSource() {
        if (StringUtils.isEmpty(properties.getNamespaceSource())) {
            return NAMESPACE_SOURCE_SPRINGBOOT;
        }
        return properties.getNamespaceSource();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy