Search in sources :

Example 56 with SaturnJobConsoleException

use of com.vip.saturn.job.console.exception.SaturnJobConsoleException in project Saturn by vipshop.

the class JobOperationRestApiControllerTest method testCreateFailAsJobAlreadyExisted.

@Test
public void testCreateFailAsJobAlreadyExisted() throws Exception {
    JobEntity jobEntity = constructJobEntity("job2");
    String errMsg = "该作业(job2)已经存在";
    willThrow(new SaturnJobConsoleException(SaturnJobConsoleException.ERROR_CODE_BAD_REQUEST, errMsg)).given(restApiService).createJob(any(String.class), any(JobConfig.class));
    MvcResult result = mvc.perform(post("/rest/v1/domain/jobs").contentType(MediaType.APPLICATION_JSON).content(jobEntity.toJSON())).andExpect(status().isBadRequest()).andReturn();
    String message = fetchErrorMessage(result);
    assertEquals("error message not equal", "该作业(job2)已经存在", message);
}
Also used : SaturnJobConsoleException(com.vip.saturn.job.console.exception.SaturnJobConsoleException) MvcResult(org.springframework.test.web.servlet.MvcResult) RestApiJobConfig(com.vip.saturn.job.console.domain.RestApiJobConfig) JobConfig(com.vip.saturn.job.console.domain.JobConfig) Test(org.junit.Test) WebMvcTest(org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest) AbstractSaturnConsoleTest(com.vip.saturn.job.console.AbstractSaturnConsoleTest)

Example 57 with SaturnJobConsoleException

use of com.vip.saturn.job.console.exception.SaturnJobConsoleException in project Saturn by vipshop.

the class SaturnConsoleUtils method exportFile.

public static void exportFile(HttpServletResponse response, InputStream inputStream, String exportFileName) throws SaturnJobConsoleException {
    try {
        response.setContentType("application/octet-stream");
        response.setHeader("Content-disposition", "attachment; filename=" + new String(exportFileName.getBytes("UTF-8"), "ISO8859-1"));
        try (BufferedInputStream bis = new BufferedInputStream(inputStream);
            BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {
            byte[] buff = new byte[2048];
            int bytesRead;
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
        }
    } catch (Exception e) {
        throw new SaturnJobConsoleException(e);
    }
}
Also used : SaturnJobConsoleException(com.vip.saturn.job.console.exception.SaturnJobConsoleException) SaturnJobConsoleException(com.vip.saturn.job.console.exception.SaturnJobConsoleException)

Example 58 with SaturnJobConsoleException

use of com.vip.saturn.job.console.exception.SaturnJobConsoleException in project Saturn by vipshop.

the class JobServiceImpl method updateJobCron.

@Transactional(rollbackFor = Exception.class)
@Override
public void updateJobCron(String namespace, String jobName, String cron, Map<String, String> customContext, String updatedBy) throws SaturnJobConsoleException {
    String cron0 = cron;
    if (cron0 != null && !cron0.trim().isEmpty()) {
        try {
            cron0 = cron0.trim();
            CronExpression.validateExpression(cron0);
        } catch (ParseException e) {
            throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, "The cron expression is invalid: " + cron);
        }
    } else {
        cron0 = "";
    }
    CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = registryCenterService.getCuratorFrameworkOp(namespace);
    if (curatorFrameworkOp.checkExists(JobNodePath.getConfigNodePath(jobName))) {
        String newCustomContextStr = null;
        String oldCustomContextStr = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, CONFIG_ITEM_CUSTOM_CONTEXT));
        Map<String, String> oldCustomContextMap = toCustomContext(oldCustomContextStr);
        if (customContext != null && !customContext.isEmpty()) {
            oldCustomContextMap.putAll(customContext);
            newCustomContextStr = toCustomContext(oldCustomContextMap);
            if (newCustomContextStr.length() > 8000) {
                throw new SaturnJobConsoleException("The all customContext is out of db limit (Varchar[8000])");
            }
            if (newCustomContextStr.getBytes().length > 1024 * 1024) {
                throw new SaturnJobConsoleException("The all customContext is out of zk limit memory(1M)");
            }
        }
        String newCron = null;
        String oldCron = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, CONFIG_ITEM_CRON));
        if (cron0 != null && oldCron != null && !cron0.equals(oldCron.trim())) {
            newCron = cron0;
        }
        if (newCustomContextStr != null || newCron != null) {
            saveCronToDb(jobName, curatorFrameworkOp, newCustomContextStr, newCron, updatedBy);
        }
        if (newCustomContextStr != null) {
            curatorFrameworkOp.update(JobNodePath.getConfigNodePath(jobName, CONFIG_ITEM_CUSTOM_CONTEXT), newCustomContextStr);
        }
        if (newCron != null) {
            curatorFrameworkOp.update(JobNodePath.getConfigNodePath(jobName, CONFIG_ITEM_CRON), newCron);
        }
    } else {
        throw new SaturnJobConsoleException(ERROR_CODE_NOT_EXISTED, "The job does not exists: " + jobName);
    }
}
Also used : CuratorRepository(com.vip.saturn.job.console.repository.zookeeper.CuratorRepository) SaturnJobConsoleException(com.vip.saturn.job.console.exception.SaturnJobConsoleException) ParseException(java.text.ParseException) CuratorFrameworkOp(com.vip.saturn.job.console.repository.zookeeper.CuratorRepository.CuratorFrameworkOp) Transactional(org.springframework.transaction.annotation.Transactional)

Example 59 with SaturnJobConsoleException

use of com.vip.saturn.job.console.exception.SaturnJobConsoleException in project Saturn by vipshop.

the class JobServiceImpl method batchSetGroups.

/**
 * 批量设置作业的分组
 *
 * @param namespace
 * @param jobNames      待设置分组的作业名集合
 * @param oldGroupNames 修改前的分组名集合
 * @param newGroupNames 修改后的分组名集合
 * @param userName      操作者
 */
@Transactional(rollbackFor = Exception.class)
@Override
public void batchSetGroups(String namespace, List<String> jobNames, List<String> oldGroupNames, List<String> newGroupNames, String userName) throws SaturnJobConsoleException {
    if (CollectionUtils.isEmpty(jobNames)) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, "请选择要分组的作业");
    }
    if (CollectionUtils.isEmpty(oldGroupNames) && CollectionUtils.isEmpty(newGroupNames)) {
        return;
    }
    List<String> oldGroupNamesTemp = null;
    List<String> newGroupNamesTemp = null;
    Pattern pattern = Pattern.compile("[`!@#$%^!@#¥%……&*()|{}【】‘;:”“’。,、? ]");
    if (!CollectionUtils.isEmpty(oldGroupNames)) {
        for (String groupName : oldGroupNames) {
            validateGroupName(groupName, pattern);
        }
        oldGroupNamesTemp = new ArrayList<>(oldGroupNames);
    }
    if (!CollectionUtils.isEmpty(newGroupNames)) {
        for (String groupName : newGroupNames) {
            validateGroupName(groupName, pattern);
        }
        newGroupNamesTemp = new ArrayList<>(newGroupNames);
    }
    // 新旧分组集合元素相同,无需处理
    if (!CollectionUtils.isEmpty(oldGroupNames) && !CollectionUtils.isEmpty(newGroupNames)) {
        Collections.sort(oldGroupNames);
        Collections.sort(newGroupNames);
        if (oldGroupNames.toString().equals(newGroupNames.toString())) {
            return;
        }
    }
    // 中存在,newGroupNamesTemp 中不存在的元素),即删除的分组
    if (!CollectionUtils.isEmpty(oldGroupNamesTemp) && !CollectionUtils.isEmpty(newGroupNamesTemp)) {
        oldGroupNamesTemp.removeAll(newGroupNamesTemp);
    }
    // 前端操作有删除分组,则将删除的分组从数据库中删除
    if (!CollectionUtils.isEmpty(oldGroupNamesTemp)) {
        for (String groupName : oldGroupNamesTemp) {
            currentJobConfigService.batchSetGroups(namespace, jobNames, groupName, userName);
        }
    }
    // 中不存在的元素),即新增的分组
    if (!CollectionUtils.isEmpty(newGroupNames) && !CollectionUtils.isEmpty(oldGroupNames)) {
        newGroupNames.removeAll(oldGroupNames);
    }
    // 前端操作有新增分组,则将新增的分组追加到原有分组后面,用英文逗号连接
    if (!CollectionUtils.isEmpty(newGroupNames)) {
        for (String groupName : newGroupNames) {
            currentJobConfigService.addToGroups(namespace, jobNames, groupName, userName);
        }
    }
}
Also used : Pattern(java.util.regex.Pattern) SaturnJobConsoleException(com.vip.saturn.job.console.exception.SaturnJobConsoleException) Transactional(org.springframework.transaction.annotation.Transactional)

Example 60 with SaturnJobConsoleException

use of com.vip.saturn.job.console.exception.SaturnJobConsoleException in project Saturn by vipshop.

the class JobServiceImpl method convertJobConfig.

private JobConfig convertJobConfig(int sheetNumber, int rowNumber, Cell[] rowCells) throws SaturnJobConsoleException {
    String jobName = getContents(rowCells, 0);
    if (jobName == null || jobName.trim().isEmpty()) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 1, "作业名必填。"));
    }
    if (!jobName.matches("[0-9a-zA-Z_]*")) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 1, "作业名只允许包含:数字0-9、小写字符a-z、大写字符A-Z、下划线_。"));
    }
    JobConfig jobConfig = new JobConfig();
    jobConfig.setJobName(jobName);
    String jobType = getContents(rowCells, 1);
    if (jobType == null || jobType.trim().isEmpty()) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 2, "作业类型必填。"));
    }
    JobType jobTypeObj = JobType.getJobType(jobType);
    if (jobTypeObj == JobType.UNKNOWN_JOB) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 2, "作业类型未知。"));
    }
    jobConfig.setJobType(jobType);
    String jobClass = getContents(rowCells, 2);
    if (JobType.isJava(jobTypeObj) && (jobClass == null || jobClass.trim().isEmpty())) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 3, "对于java作业,作业实现类必填。"));
    }
    jobConfig.setJobClass(jobClass);
    String cron = getContents(rowCells, 3);
    if (JobType.isCron(jobTypeObj)) {
        if (cron == null || cron.trim().isEmpty()) {
            throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 4, "对于cron作业,cron表达式必填。"));
        }
        cron = cron.trim();
        try {
            CronExpression.validateExpression(cron);
        } catch (ParseException e) {
            throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 4, "cron表达式语法有误," + e));
        }
    } else {
        // 其他类型的不需要持久化保存cron表达式
        cron = "";
    }
    jobConfig.setCron(cron);
    jobConfig.setDescription(getContents(rowCells, 4));
    jobConfig.setLocalMode(Boolean.valueOf(getContents(rowCells, 5)));
    int shardingTotalCount = 1;
    if (jobConfig.getLocalMode()) {
        jobConfig.setShardingTotalCount(shardingTotalCount);
    } else {
        String tmp = getContents(rowCells, 6);
        if (tmp != null && !tmp.trim().isEmpty()) {
            try {
                shardingTotalCount = Integer.parseInt(tmp);
            } catch (NumberFormatException e) {
                throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 7, "分片数有误," + e));
            }
        } else {
            throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 7, "分片数必填"));
        }
        if (shardingTotalCount < 1) {
            throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 7, "分片数不能小于1"));
        }
        jobConfig.setShardingTotalCount(shardingTotalCount);
    }
    int timeoutSeconds = 0;
    try {
        String tmp = getContents(rowCells, 7);
        if (tmp != null && !tmp.trim().isEmpty()) {
            timeoutSeconds = Integer.parseInt(tmp.trim());
        }
    } catch (NumberFormatException e) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 8, "超时(Kill线程/进程)时间有误," + e));
    }
    jobConfig.setTimeoutSeconds(timeoutSeconds);
    jobConfig.setJobParameter(getContents(rowCells, 8));
    String shardingItemParameters = getContents(rowCells, 9);
    if (jobConfig.getLocalMode()) {
        if (shardingItemParameters == null || shardingItemParameters.trim().isEmpty()) {
            throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 10, "对于本地模式作业,分片参数必填。"));
        } else {
            String[] split = shardingItemParameters.split(",");
            boolean includeXing = false;
            for (String tmp : split) {
                String[] split2 = tmp.split("=");
                if ("*".equalsIgnoreCase(split2[0].trim())) {
                    includeXing = true;
                    break;
                }
            }
            if (!includeXing) {
                throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 10, "对于本地模式作业,分片参数必须包含如*=xx。"));
            }
        }
    } else if ((shardingTotalCount > 0) && (shardingItemParameters == null || shardingItemParameters.trim().isEmpty() || shardingItemParameters.split(",").length < shardingTotalCount)) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 10, "分片参数不能小于分片总数。"));
    }
    jobConfig.setShardingItemParameters(shardingItemParameters);
    jobConfig.setQueueName(getContents(rowCells, 10));
    jobConfig.setChannelName(getContents(rowCells, 11));
    jobConfig.setPreferList(getContents(rowCells, 12));
    jobConfig.setUseDispreferList(!Boolean.parseBoolean(getContents(rowCells, 13)));
    int processCountIntervalSeconds = 300;
    try {
        String tmp = getContents(rowCells, 14);
        if (tmp != null && !tmp.trim().isEmpty()) {
            processCountIntervalSeconds = Integer.parseInt(tmp.trim());
        }
    } catch (NumberFormatException e) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 15, "统计处理数据量的间隔秒数有误," + e));
    }
    jobConfig.setProcessCountIntervalSeconds(processCountIntervalSeconds);
    int loadLevel = 1;
    try {
        String tmp = getContents(rowCells, 15);
        if (tmp != null && !tmp.trim().isEmpty()) {
            loadLevel = Integer.parseInt(tmp.trim());
        }
    } catch (NumberFormatException e) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 16, "负荷有误," + e));
    }
    jobConfig.setLoadLevel(loadLevel);
    jobConfig.setShowNormalLog(Boolean.valueOf(getContents(rowCells, 16)));
    jobConfig.setPausePeriodDate(getContents(rowCells, 17));
    jobConfig.setPausePeriodTime(getContents(rowCells, 18));
    jobConfig.setUseSerial(Boolean.valueOf(getContents(rowCells, 19)));
    int jobDegree = 0;
    try {
        String tmp = getContents(rowCells, 20);
        if (tmp != null && !tmp.trim().isEmpty()) {
            jobDegree = Integer.parseInt(tmp.trim());
        }
    } catch (NumberFormatException e) {
        throw new SaturnJobConsoleException(createExceptionMessage(sheetNumber, rowNumber, 21, "作业重要等级有误," + e));
    }
    jobConfig.setJobDegree(jobDegree);
    // 第21列,上报运行状态失效,由算法决定是否上报,看下面setEnabledReport时的逻辑,看addJob
    String jobMode = getContents(rowCells, 22);
    if (jobMode != null && jobMode.startsWith(com.vip.saturn.job.console.domain.JobMode.SYSTEM_PREFIX)) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 23, "作业模式有误,不能添加系统作业"));
    }
    jobConfig.setJobMode(jobMode);
    String dependencies = getContents(rowCells, 23);
    if (dependencies != null && !dependencies.matches("[0-9a-zA-Z_,]*")) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 24, "依赖的作业只允许包含:数字0-9、小写字符a-z、大写字符A-Z、下划线_、英文逗号,"));
    }
    jobConfig.setDependencies(dependencies);
    jobConfig.setGroups(getContents(rowCells, 24));
    int timeout4AlarmSeconds = 0;
    try {
        String tmp = getContents(rowCells, 25);
        if (tmp != null && !tmp.trim().isEmpty()) {
            timeout4AlarmSeconds = Integer.parseInt(tmp.trim());
        }
    } catch (NumberFormatException e) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 26, "超时(告警)时间有误," + e));
    }
    jobConfig.setTimeout4AlarmSeconds(timeout4AlarmSeconds);
    String timeZone = getContents(rowCells, 26);
    if (timeZone == null || timeZone.trim().length() == 0) {
        timeZone = SaturnConstants.TIME_ZONE_ID_DEFAULT;
    } else {
        timeZone = timeZone.trim();
        if (!SaturnConstants.TIME_ZONE_IDS.contains(timeZone)) {
            throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 27, "时区有误"));
        }
    }
    jobConfig.setTimeZone(timeZone);
    Boolean failover = null;
    String failoverStr = getContents(rowCells, 27);
    if (StringUtils.isNotBlank(failoverStr)) {
        failover = Boolean.valueOf(failoverStr.trim());
        if (failover) {
            if (jobConfig.getLocalMode()) {
                throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 28, "本地模式不支持failover"));
            }
            if (JobType.isMsg(jobTypeObj)) {
                throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 28, "消息作业不支持failover"));
            }
        // 如果不上报运行状态,则强制设置为false
        // 上报运行状态失效,由算法决定是否上报,看下面setEnabledReport时的逻辑,看addJob
        }
    }
    jobConfig.setFailover(failover);
    Boolean rerun = null;
    String rerunStr = getContents(rowCells, 28);
    if (StringUtils.isNotBlank(rerunStr)) {
        rerun = Boolean.valueOf(rerunStr.trim());
        if (rerun) {
            if (JobType.isMsg(jobTypeObj)) {
                throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 29, "消息作业不支持rerun"));
            }
            if (JobType.isPassive(jobTypeObj)) {
                throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 29, "被动作业不支持rerun"));
            }
        // 如果不上报运行状态,则强制设置为false
        // 上报运行状态失效,由算法决定是否上报,看下面setEnabledReport时的逻辑,看addJob
        }
    }
    jobConfig.setRerun(rerun);
    String upStream = getContents(rowCells, 29);
    if (upStream != null && !upStream.matches("[0-9a-zA-Z_,]*")) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 30, "上游作业只允许包含:数字0-9、小写字符a-z、大写字符A-Z、下划线_、英文逗号,"));
    }
    jobConfig.setUpStream(upStream);
    String downStream = getContents(rowCells, 30);
    if (downStream != null && !downStream.matches("[0-9a-zA-Z_,]*")) {
        throw new SaturnJobConsoleException(ERROR_CODE_BAD_REQUEST, createExceptionMessage(sheetNumber, rowNumber, 31, "下游作业只允许包含:数字0-9、小写字符a-z、大写字符A-Z、下划线_、英文逗号,"));
    }
    jobConfig.setDownStream(downStream);
    return jobConfig;
}
Also used : SaturnJobConsoleException(com.vip.saturn.job.console.exception.SaturnJobConsoleException) ParseException(java.text.ParseException) Boolean(java.lang.Boolean)

Aggregations

SaturnJobConsoleException (com.vip.saturn.job.console.exception.SaturnJobConsoleException)190 SaturnJobConsoleHttpException (com.vip.saturn.job.console.exception.SaturnJobConsoleHttpException)56 RequestMapping (org.springframework.web.bind.annotation.RequestMapping)56 CuratorRepository (com.vip.saturn.job.console.repository.zookeeper.CuratorRepository)39 RequestResult (com.vip.saturn.job.console.domain.RequestResult)31 ParseException (java.text.ParseException)28 ResponseEntity (org.springframework.http.ResponseEntity)26 Transactional (org.springframework.transaction.annotation.Transactional)23 JobConfig4DB (com.vip.saturn.job.console.mybatis.entity.JobConfig4DB)22 CuratorFrameworkOp (com.vip.saturn.job.console.repository.zookeeper.CuratorRepository.CuratorFrameworkOp)22 IOException (java.io.IOException)19 CloseableHttpClient (org.apache.http.impl.client.CloseableHttpClient)19 StatusLine (org.apache.http.StatusLine)18 HttpEntity (org.apache.http.HttpEntity)16 Audit (com.vip.saturn.job.console.aop.annotation.Audit)13 JobConfig (com.vip.saturn.job.console.domain.JobConfig)11 HttpHeaders (org.springframework.http.HttpHeaders)11 CurrentJobConfig (com.vip.saturn.job.console.mybatis.entity.CurrentJobConfig)9 ZkCluster (com.vip.saturn.job.console.domain.ZkCluster)8 ArrayList (java.util.ArrayList)8