/**
* Copyright 2016 vip.com.
* <p>
* Licensed 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* </p>
*/
package com.vip.saturn.job.console.service.impl;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.vip.saturn.job.console.domain.*;
import com.vip.saturn.job.console.domain.ExecutionInfo.ExecutionStatus;
import com.vip.saturn.job.console.domain.JobBriefInfo.JobType;
import com.vip.saturn.job.console.exception.SaturnJobConsoleException;
import com.vip.saturn.job.console.repository.zookeeper.CuratorRepository;
import com.vip.saturn.job.console.service.JobDimensionService;
import com.vip.saturn.job.console.service.RegistryCenterService;
import com.vip.saturn.job.console.utils.*;
import com.vip.saturn.job.sharding.node.SaturnExecutorsNode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
@Service
public class JobDimensionServiceImpl implements JobDimensionService {
protected static Logger log = LoggerFactory.getLogger(JobDimensionServiceImpl.class);
@Resource
private CuratorRepository curatorRepository;
protected static Logger AUDITLOGGER = LoggerFactory.getLogger("AUDITLOG");
@Resource
private RegistryCenterService registryCenterService;
private JobBriefInfo genJobBriefInfo4tree(String jobName, CuratorRepository.CuratorFrameworkOp curatorFrameworkOp) {
JobBriefInfo jobBriefInfo = new JobBriefInfo();
jobBriefInfo.setJobName(jobName);
jobBriefInfo.setDescription(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "description")));
jobBriefInfo.setJobClass(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "jobClass")));
jobBriefInfo.setJobType(JobType.getJobType(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "jobType"))));
if (JobType.UNKOWN_JOB.equals(jobBriefInfo.getJobType())) {
if (jobBriefInfo.getJobClass() != null && jobBriefInfo.getJobClass().indexOf("SaturnScriptJob") != -1) {
jobBriefInfo.setJobType(JobType.SHELL_JOB);
} else {
jobBriefInfo.setJobType(JobType.JAVA_JOB);
}
}
return jobBriefInfo;
}
@Override
public Collection<JobBriefInfo> getAllJobsBriefInfo4Tree() {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
List<String> jobNames = new ArrayList<>();
try {
jobNames = getAllUnSystemJobs(curatorFrameworkOp);
} catch (SaturnJobConsoleException e) {
log.error(e.getMessage(), e);
}
List<JobBriefInfo> result = new ArrayList<>(jobNames.size());
for (String jobName : jobNames) {
try {
JobBriefInfo jobBriefInfo = genJobBriefInfo4tree(jobName, curatorFrameworkOp);
result.add(jobBriefInfo);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
return result;
}
@Override
public List<String> getAllJobs(CuratorRepository.CuratorFrameworkOp curatorFrameworkOp) throws SaturnJobConsoleException {
List<String> allJobs = new ArrayList<>();
if(curatorFrameworkOp == null) {
curatorFrameworkOp = curatorRepository.inSessionClient();
}
String jobsNodePath = JobNodePath.get$JobsNodePath();
if (curatorFrameworkOp.checkExists(jobsNodePath)) {
List<String> jobs = curatorFrameworkOp.getChildren(jobsNodePath);
if (jobs != null && jobs.size() > 0) {
for (String job : jobs) {
if (curatorFrameworkOp.checkExists(JobNodePath.getConfigNodePath(job))) {// 如果config节点存在才视为正常作业,其他异常作业在其他功能操作时也忽略
allJobs.add(job);
}
}
}
}
Collections.sort(allJobs);
return allJobs;
}
@Override
public List<String> getAllUnSystemJobs(CuratorRepository.CuratorFrameworkOp curatorFrameworkOp) throws SaturnJobConsoleException {
if(curatorFrameworkOp == null) {
curatorFrameworkOp = curatorRepository.inSessionClient();
}
List<String> allJobs = getAllJobs(curatorFrameworkOp);
Iterator<String> iterator = allJobs.iterator();
while(iterator.hasNext()) {
String job = iterator.next();
String jobMode = JobNodePath.getConfigNodePath(job, "jobMode");
if(curatorFrameworkOp.checkExists(jobMode)) {
String data = curatorFrameworkOp.getData(jobMode);
if(data != null && data.startsWith(JobMode.SYSTEM_PREFIX)) {
iterator.remove();
}
}
}
return allJobs;
}
@Override
public List<JobConfig> getDependentJobsStatus(String jobName) throws SaturnJobConsoleException {
List<JobConfig> jobConfigs = new ArrayList<>();
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
String dependencies = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "dependencies"));
if(dependencies != null) {
List<String> allUnSystemJobs = getAllUnSystemJobs(curatorFrameworkOp);
String[] split = dependencies.split(",");
if(split != null) {
for(String tmp : split) {
if(tmp != null) {
String dependency = tmp.trim();
if(dependency.length() > 0) {
if(!dependency.equals(jobName) && allUnSystemJobs.contains(dependency)) {
JobConfig jobConfig = new JobConfig();
jobConfig.setJobName(dependency);
jobConfig.setEnabled(Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(dependency, "enabled"))));
jobConfigs.add(jobConfig);
}
}
}
}
}
}
return jobConfigs;
}
@Override
public List<JobConfig> getDependedJobsStatus(String jobName) throws SaturnJobConsoleException {
List<JobConfig> jobConfigs = new ArrayList<>();
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
List<String> allUnSystemJobs = getAllUnSystemJobs(curatorFrameworkOp);
if(allUnSystemJobs != null) {
for(String job : allUnSystemJobs) {
if(!job.equals(jobName)) {
String dependencies = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(job, "dependencies"));
if (dependencies != null) {
String[] split = dependencies.split(",");
if (split != null) {
for (String tmp : split) {
if (tmp != null) {
String dependency = tmp.trim();
if (dependency.equals(jobName)) {
JobConfig jobConfig = new JobConfig();
jobConfig.setJobName(job);
jobConfig.setEnabled(Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(job, "enabled"))));
jobConfigs.add(jobConfig);
break;
}
}
}
}
}
}
}
}
return jobConfigs;
}
@Override
public Collection<JobBriefInfo> getAllJobsBriefInfo(String sessionZkKey, String namespace) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
List<String> jobNames = new ArrayList<>();
try {
jobNames = getAllUnSystemJobs(curatorFrameworkOp);
} catch (SaturnJobConsoleException e) {
log.error(e.getMessage(), e);
}
List<JobBriefInfo> result = new ArrayList<>(jobNames.size());
for (String jobName : jobNames) {
try{
if (!curatorFrameworkOp.checkExists(JobNodePath.getConfigNodePath(jobName))) {
continue;
}
JobBriefInfo jobBriefInfo = genJobBriefInfo4tree(jobName, curatorFrameworkOp);
jobBriefInfo.setIsJobEnabled(isJobEnabled(jobName));
jobBriefInfo.setStatus(getJobStatus(jobName));
jobBriefInfo.setJobParameter(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "jobParameter")));
jobBriefInfo.setShardingItemParameters(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "shardingItemParameters")));
jobBriefInfo.setQueueName(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "queueName")));
jobBriefInfo.setChannelName(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "channelName")));
jobBriefInfo.setLoadLevel(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "loadLevel")));
String jobDegree = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "jobDegree"));
if(Strings.isNullOrEmpty(jobDegree)){
jobDegree = "0";
}
jobBriefInfo.setJobDegree(jobDegree);
jobBriefInfo.setShardingTotalCount(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "shardingTotalCount")));
String timeout4AlarmSecondsStr = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "timeout4AlarmSeconds"));
if(Strings.isNullOrEmpty(timeout4AlarmSecondsStr)) {
jobBriefInfo.setTimeout4AlarmSeconds(0);
} else {
jobBriefInfo.setTimeout4AlarmSeconds(Integer.parseInt(timeout4AlarmSecondsStr));
}
jobBriefInfo.setTimeoutSeconds(Integer.parseInt(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "timeoutSeconds"))));
jobBriefInfo.setPausePeriodDate(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "pausePeriodDate")));
jobBriefInfo.setPausePeriodTime(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "pausePeriodTime")));
jobBriefInfo.setShowNormalLog(Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "showNormalLog"))));
jobBriefInfo.setLocalMode(Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "localMode"))));
jobBriefInfo.setUseSerial(Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "useSerial"))));
jobBriefInfo.setUseDispreferList((Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "useDispreferList")))));
jobBriefInfo.setProcessCountIntervalSeconds(Integer.parseInt(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "processCountIntervalSeconds"))));
jobBriefInfo.setJobRate(geJobRunningInfo(jobName));
jobBriefInfo.setGroups(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "groups")));
String preferList = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "preferList"));
StringBuilder allPreferExecutorsBuilder = new StringBuilder();
if(!Strings.isNullOrEmpty(preferList)){
List<String> executors = null;
String executorsNodePath = SaturnExecutorsNode.getExecutorsNodePath();
if(curatorFrameworkOp.checkExists(executorsNodePath)) {
executors = curatorFrameworkOp.getChildren(executorsNodePath);
}
List<String> containerTaskIds = null;
String containerTaskIdsNodePath = ContainerNodePath.getDcosTasksNodePath();
if (curatorFrameworkOp.checkExists(containerTaskIdsNodePath)) {
containerTaskIds = curatorFrameworkOp.getChildren(containerTaskIdsNodePath);
}
boolean hasExecutors = !CollectionUtils.isEmpty(executors);
String[] preferExecutorList = preferList.split(",");
for(String preferExecutor : preferExecutorList){
boolean isContainerPrefer = preferExecutor.startsWith("@");
if(hasExecutors && !executors.contains(preferExecutor) && !isContainerPrefer){ //NOSONAR
allPreferExecutorsBuilder.append(preferExecutor + "(已删除)").append(",");
} else if (isContainerPrefer) {
String preferTaskId = preferExecutor.substring(1);// 容器资源去掉@符号
if (!CollectionUtils.isEmpty(containerTaskIds) && containerTaskIds.contains(preferTaskId)) {// 过滤掉preferList中有,但实际上已被销毁的容器
allPreferExecutorsBuilder.append(preferTaskId + "(容器资源)").append(",");
}
} else{
allPreferExecutorsBuilder.append(preferExecutor).append(",");
}
}
if(!Strings.isNullOrEmpty(allPreferExecutorsBuilder.toString())){
jobBriefInfo.setPreferList(allPreferExecutorsBuilder.substring(0,allPreferExecutorsBuilder.length()-1));
}
jobBriefInfo.setMigrateEnabled(isMigrateEnabled(preferList, containerTaskIds));
} else {
jobBriefInfo.setMigrateEnabled(false);
}
String timeZone = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "timeZone"));
if(Strings.isNullOrEmpty(timeZone)) {
jobBriefInfo.setTimeZone(SaturnConstants.TIME_ZONE_ID_DEFAULT);
} else {
jobBriefInfo.setTimeZone(timeZone);
}
jobBriefInfo.setCron(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "cron")));
if(!JobStatus.STOPPED.equals(jobBriefInfo.getStatus())){// 作业如果是STOPPED状态,不需要显示已分配的executor
String executorsPath = JobNodePath.getServerNodePath(jobName);
if(curatorFrameworkOp.checkExists(executorsPath)) {
List<String> executors = curatorFrameworkOp.getChildren(executorsPath);
if (executors != null && !executors.isEmpty()) {
StringBuilder shardingListSb = new StringBuilder();
for(String executor : executors){
String sharding = curatorFrameworkOp.getData(JobNodePath.getServerNodePath(jobName,executor,"sharding"));
if(!Strings.isNullOrEmpty(sharding)){
shardingListSb.append(executor).append(",");
}
}
if(shardingListSb != null && shardingListSb.length() > 0){
jobBriefInfo.setShardingList(shardingListSb.substring(0, shardingListSb.length() - 1));
}
}
}
}
// set nextfireTime
/*String executionRootpath = JobNodePath.getExecutionNodePath(jobName);
if (curatorFrameworkOp.checkExists(executionRootpath)) {
List<String> items = curatorFrameworkOp.getChildren(executionRootpath);
if (items != null && !items.isEmpty()) {
String nextFireTime = curatorFrameworkOp.getData(JobNodePath.getExecutionNodePath(jobName, "0", "nextFireTime"));
if (nextFireTime != null) {
jobBriefInfo.setNextFireTime(nextFireTime);
}
}
}*/
result.add(jobBriefInfo);
}catch(Exception e){
log.error(e.getMessage(), e);
continue;
}
}
Collections.sort(result);
return result;
}
private boolean isMigrateEnabled(String preferList, List<String> tasks) {
if (tasks == null || tasks.isEmpty()) {
return false;
}
List<String> preferTasks = new ArrayList<>();
String[] split = preferList.split(",");
for (int i = 0; i < split.length; i++) {
String prefer = split[i].trim();
if (prefer.startsWith("@")) {
preferTasks.add(prefer.substring(1));
}
}
if(!preferTasks.isEmpty()) {
for (String task : tasks) {
if (!preferTasks.contains(task)) {
return true;
}
}
}
return false;
}
public String geJobRunningInfo(final String jobName) {
String serverNodePath = JobNodePath.getServerNodePath(jobName);
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
if(!curatorFrameworkOp.checkExists(serverNodePath)) {
return "";
}
List<String> servers = curatorFrameworkOp.getChildren(serverNodePath);
// server为空表示没有Server工作,这个时候作业状态应该是Crashed
if (servers == null || servers.size() == 0) {
return "";
}
int processSuccessCount = 0;
int processFailureCount = 0;
for (String each : servers) {
String processSuccessCountStr = curatorFrameworkOp
.getData(JobNodePath.getServerNodePath(jobName, each, "processSuccessCount"));
if (!Strings.isNullOrEmpty(processSuccessCountStr)) {
processSuccessCount += Integer.parseInt(processSuccessCountStr);
}
String processFailureCountStr = curatorFrameworkOp
.getData(JobNodePath.getServerNodePath(jobName, each, "processFailureCount"));
if (!Strings.isNullOrEmpty(processFailureCountStr)) {
processFailureCount += Integer.parseInt(processFailureCountStr);
}
}
int count = processSuccessCount;
int total = processSuccessCount + processFailureCount;
if (total == 0) {
return "";
}
NumberFormat numberFormat = NumberFormat.getInstance();
numberFormat.setMaximumFractionDigits(2);
String result = numberFormat.format((double) count / (double) total * 100);
return result + "%";
}
@Override
public JobStatus getJobStatus(final String jobName) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
// see if all the shards is finished.
List<String> executionItems = curatorFrameworkOp.getChildren(JobNodePath.getExecutionNodePath(jobName));
boolean isAllShardsFinished = true;
if (executionItems != null && !executionItems.isEmpty()) {
for (String itemStr: executionItems) {
boolean isItemCompleted = curatorFrameworkOp.checkExists(JobNodePath.getExecutionNodePath(jobName, itemStr, "completed"));
boolean isItemRunning = curatorFrameworkOp.checkExists(JobNodePath.getExecutionNodePath(jobName, itemStr, "running"));
// if executor is kill by -9 while it is running, completed node won't exists as well as running node.
// under this circumstance, we consider it is completed.
if (!isItemCompleted && isItemRunning) {
isAllShardsFinished = false;
break;
}
}
}
// see if the job is enabled or not.
boolean enabled = Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "enabled")));
if (enabled) {
if (isAllShardsFinished) {
return JobStatus.READY;
}
return JobStatus.RUNNING;
} else {
if (isAllShardsFinished) {
return JobStatus.STOPPED;
}
return JobStatus.STOPPING;
}
}
@Override
public JobSettings getJobSettings(final String jobName, RegistryCenterConfiguration configInSession) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
JobSettings result = new JobSettings();
result.setJobName(jobName);
result.setJobClass(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "jobClass")));
result.setShardingTotalCount(Integer.parseInt(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "shardingTotalCount"))));
String timeZone = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "timeZone"));
if(Strings.isNullOrEmpty(timeZone)) {
result.setTimeZone(SaturnConstants.TIME_ZONE_ID_DEFAULT);
} else {
result.setTimeZone(timeZone);
}
result.setTimeZonesProvided(Arrays.asList(TimeZone.getAvailableIDs()));
result.setCron(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "cron")));
result.setPausePeriodDate(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "pausePeriodDate")));
result.setPausePeriodTime(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "pausePeriodTime")));
result.setShardingItemParameters(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "shardingItemParameters")));
result.setJobParameter(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "jobParameter")));
result.setProcessCountIntervalSeconds(Integer.parseInt(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "processCountIntervalSeconds"))));
String timeout4AlarmSecondsStr = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "timeout4AlarmSeconds"));
if(Strings.isNullOrEmpty(timeout4AlarmSecondsStr)) {
result.setTimeout4AlarmSeconds(0);
} else {
result.setTimeout4AlarmSeconds(Integer.parseInt(timeout4AlarmSecondsStr));
}
result.setTimeoutSeconds(
Integer.parseInt(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "timeoutSeconds"))));
String lv = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "loadLevel"));
if (Strings.isNullOrEmpty(lv)) {
result.setLoadLevel(1);
} else {
result.setLoadLevel(Integer.parseInt(lv));
}
String jobDegree = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "jobDegree"));
if (Strings.isNullOrEmpty(jobDegree)) {
result.setJobDegree(0);
} else {
result.setJobDegree(Integer.parseInt(jobDegree));
}
result.setEnabled(Boolean.valueOf(JobNodePath.getConfigNodePath(jobName, "enabled")));//默认是禁用的
result.setPreferList(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "preferList")));
result.setPreferListCandidate(getAllExecutors(jobName));
String useDispreferList = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "useDispreferList"));
if(Strings.isNullOrEmpty(useDispreferList)){
result.setUseDispreferList(null);
}else{
result.setUseDispreferList(Boolean.valueOf(useDispreferList));
}
result.setUseSerial(Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "useSerial"))));
result.setLocalMode(Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "localMode"))));
// result.setFailover(Boolean.valueOf(curatorRepository.getData(JobNodePath.getConfigNodePath(jobName, "failover"))));
result.setDependencies(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "dependencies")));
result.setGroups(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "groups")));
try {
List<String> allUnSystemJobs = getAllUnSystemJobs(curatorFrameworkOp);
if(allUnSystemJobs != null) {
allUnSystemJobs.remove(jobName);
result.setDependenciesProvided(allUnSystemJobs);
}
} catch (SaturnJobConsoleException e) {
log.error(e.getMessage(), e);
}
result.setDescription(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "description")));
result.setQueueName(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "queueName")));
result.setChannelName(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "channelName")));
if (curatorFrameworkOp.checkExists(JobNodePath.getConfigNodePath(jobName, "showNormalLog")) == false) {
curatorFrameworkOp.create(JobNodePath.getConfigNodePath(jobName, "showNormalLog"));
}
String jobType = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "jobType"));
result.setJobType(jobType);
String enabledReport = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "enabledReport"));
Boolean enabledReportValue = Boolean.valueOf(enabledReport);
if (Strings.isNullOrEmpty(enabledReport)) {
if(JobType.JAVA_JOB.name().equals(jobType) || JobType.SHELL_JOB.name().equals(jobType)){
enabledReportValue = true;
}else{
enabledReportValue = false;
}
}
result.setEnabledReport(enabledReportValue);
// 兼容旧版没有msg_job。
if (StringUtils.isBlank(result.getJobType())) {
if (result.getJobClass().indexOf("script") > 0) {
result.setJobType(JobType.SHELL_JOB.name());
} else {
result.setJobType(JobType.JAVA_JOB.name());
}
}
result.setShowNormalLog(Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "showNormalLog"))));
return result;
}
@Override
public JobConfig getHistoryJobConfigByHistoryId(Long historyId) throws SaturnJobConsoleException {
return null;
}
@Override
public String updateJobSettings(final JobSettings jobSettings, RegistryCenterConfiguration configInSession) {
// Modify JobSettings.updateFields() sync, if the update fields changed.
jobSettings.setDefaultValues();
BooleanWrapper bw = new BooleanWrapper(false);
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
try {
curatorFrameworkOp.inTransaction()
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "jobMode"), jobSettings.getJobMode(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "shardingTotalCount"), jobSettings.getShardingTotalCount(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "loadLevel"), jobSettings.getLoadLevel(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "jobDegree"), jobSettings.getJobDegree(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "enabledReport"), jobSettings.getEnabledReport(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "timeZone"), StringUtils.trim(jobSettings.getTimeZone()), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "cron"), StringUtils.trim(jobSettings.getCron()), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "pausePeriodDate"), jobSettings.getPausePeriodDate(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "pausePeriodTime"), jobSettings.getPausePeriodTime(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "shardingItemParameters"), jobSettings.getShardingItemParameters(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "jobParameter"), jobSettings.getJobParameter(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "processCountIntervalSeconds"), jobSettings.getProcessCountIntervalSeconds(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "timeout4AlarmSeconds"), jobSettings.getTimeout4AlarmSeconds(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "timeoutSeconds"), jobSettings.getTimeoutSeconds(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "dependencies"), jobSettings.getDependencies(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "groups"), jobSettings.getGroups(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "description"), jobSettings.getDescription(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "channelName"), StringUtils.trim(jobSettings.getChannelName()), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "queueName"), StringUtils.trim(jobSettings.getQueueName()), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "showNormalLog"), jobSettings.getShowNormalLog(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "preferList"), jobSettings.getPreferList(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "useDispreferList"), jobSettings.getUseDispreferList(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "failover"), jobSettings.getFailover(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "localMode"), jobSettings.getLocalMode(), bw)
.replaceIfchanged(JobNodePath.getConfigNodePath(jobSettings.getJobName(), "useSerial"), jobSettings.getUseSerial(), bw)
.commit();
if(jobSettings.getEnabledReport() != null && !jobSettings.getEnabledReport()){// 当enabledReport关闭上报时,要清理execution节点
log.info("the switch of enabledReport set to false, now delete the execution zk node");
String executionNodePath = JobNodePath.getExecutionNodePath(jobSettings.getJobName());
if(curatorFrameworkOp.checkExists(executionNodePath)){
curatorFrameworkOp.deleteRecursive(executionNodePath);
}
}
} catch (Exception e) {
log.error("update settings to zk failed: {}", e.getMessage());
log.error(e.getMessage(),e);
return e.getMessage();
}
return null;
}
@Override
public Collection<JobServer> getServers(final String jobName) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
String serverNodePath = JobNodePath.getServerNodePath(jobName);
List<String> serverIps = new ArrayList<>();
if(curatorFrameworkOp.checkExists(serverNodePath)) {
serverIps = curatorFrameworkOp.getChildren(serverNodePath);
}
String leaderIp = curatorFrameworkOp.getData(JobNodePath.getLeaderNodePath(jobName, "election/host"));
Collection<JobServer> result = new ArrayList<>(serverIps.size());
for (String each : serverIps) {
result.add(getJobServer(jobName, leaderIp, each));
}
return result;
}
@Override
public void getServersVersion(final String jobName,List<HealthCheckJobServer> allJobServers,RegistryCenterConfiguration registryCenterConfig) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
String serverNodePath = JobNodePath.getServerNodePath(jobName);
List<String> executorNames = new ArrayList<>();
if(curatorFrameworkOp.checkExists(serverNodePath)) {
executorNames = curatorFrameworkOp.getChildren(serverNodePath);
}
for (String executorName : executorNames) {
if(allJobServers.size() >= SaturnConstants.HEALTH_CHECK_VERSION_MAX_SIZE){// 容量控制,最多查询10000条
break;
}
allJobServers.add(getJobServerVersion(jobName, executorName, registryCenterConfig));
}
}
private JobServer getJobServer(final String jobName, final String leaderIp, final String serverIp) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
JobServer result = new JobServer();
result.setExecutorName(serverIp);
result.setIp(curatorFrameworkOp.getData(JobNodePath.getServerNodePath(jobName, serverIp, "ip")));
result.setVersion(curatorFrameworkOp.getData(JobNodePath.getServerNodePath(jobName, serverIp, "version")));
String processSuccessCount = curatorFrameworkOp.getData(JobNodePath.getServerNodePath(jobName, serverIp, "processSuccessCount"));
result.setProcessSuccessCount(null == processSuccessCount ? 0 : Integer.parseInt(processSuccessCount));
String processFailureCount = curatorFrameworkOp.getData(JobNodePath.getServerNodePath(jobName, serverIp, "processFailureCount"));
result.setProcessFailureCount(null == processFailureCount ? 0 : Integer.parseInt(processFailureCount));
result.setSharding(curatorFrameworkOp.getData(JobNodePath.getServerNodePath(jobName, serverIp, "sharding")));
result.setStatus(getServerStatus(jobName, serverIp));
result.setLeader(serverIp.equals(leaderIp));
result.setJobStatus(getJobStatus(jobName));
return result;
}
private HealthCheckJobServer getJobServerVersion(final String jobName, final String executorName, RegistryCenterConfiguration registryCenterConfig) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
HealthCheckJobServer result = new HealthCheckJobServer();
result.setExecutorName(executorName);
result.setJobName(jobName);
result.setNamespace(registryCenterConfig.getNamespace());
result.setVersion(curatorFrameworkOp.getData(JobNodePath.getServerNodePath(jobName, executorName, "version")));
return result;
}
private ServerStatus getServerStatus(final String jobName, final String serverIp) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
String ip = curatorFrameworkOp.getData(ExecutorNodePath.getExecutorNodePath(serverIp, "ip"));
return ServerStatus.getServerStatus(ip);
}
@Override
public Collection<ExecutionInfo> getExecutionInfo(final String jobName) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
if(JobStatus.STOPPED.equals(getJobStatus(jobName))){
return Collections.emptyList();
}
// update report node
curatorFrameworkOp.update(JobNodePath.getReportPath(jobName), System.currentTimeMillis());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
}
String executionRootpath = JobNodePath.getExecutionNodePath(jobName);
if (!curatorFrameworkOp.checkExists(executionRootpath)) {
return Collections.emptyList();
}
List<String> items = curatorFrameworkOp.getChildren(executionRootpath);
List<ExecutionInfo> result = new ArrayList<>(items.size());
for (String each : items) {
if(getRunningIP(each, jobName) != null) { // || hasFailoverExecutor(each, jobName)
result.add(getExecutionInfo(jobName, each));
}
}
Collections.sort(result);
return result;
}
@Override
public ExecutionInfo getExecutionJobLog(String jobName, int item) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
ExecutionInfo result = new ExecutionInfo();
String logMsg = curatorFrameworkOp.getData(JobNodePath.getExecutionNodePath(jobName, String.valueOf(item), "jobLog"));
result.setLogMsg(logMsg);
return result;
}
private ExecutionInfo getExecutionInfo(final String jobName, final String item) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
ExecutionInfo result = new ExecutionInfo();
result.setJobName(jobName);
result.setItem(Integer.parseInt(item));
boolean running = curatorFrameworkOp.checkExists(JobNodePath.getExecutionNodePath(jobName, item, "running"));
boolean completed = curatorFrameworkOp.checkExists(JobNodePath.getExecutionNodePath(jobName, item, "completed"));
boolean failed = curatorFrameworkOp.checkExists(JobNodePath.getExecutionNodePath(jobName, item, "failed"));
boolean timeout = curatorFrameworkOp.checkExists(JobNodePath.getExecutionNodePath(jobName, item, "timeout"));
String enabledReportNodePath = JobNodePath.getConfigNodePath(jobName, "enabledReport");
boolean isEnabledReport = false;
if (curatorFrameworkOp.checkExists(enabledReportNodePath)) {
isEnabledReport = Boolean.valueOf(curatorFrameworkOp.getData(enabledReportNodePath));
}else{
String jobType = JobNodePath.getConfigNodePath(jobName, "jobType");
if(JobType.JAVA_JOB.name().equals(jobType) || JobType.SHELL_JOB.name().equals(jobType)){
isEnabledReport = true;
}
}
result.setStatus(ExecutionStatus.getExecutionStatus(running, completed, failed, timeout, isEnabledReport));
String jobMsg = curatorFrameworkOp.getData(JobNodePath.getExecutionNodePath(jobName, item, "jobMsg"));
result.setJobMsg(jobMsg);
String runningIp = getRunningIP(item, jobName);
result.setRunningIp(runningIp == null ? "未找到" : runningIp);
if (curatorFrameworkOp.checkExists(JobNodePath.getExecutionNodePath(jobName, item, "failover"))) {
result.setFailoverExecutor(curatorFrameworkOp.getData(JobNodePath.getExecutionNodePath(jobName, item, "failover")));
}
String timeZoneStr = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "timeZone"));
if(timeZoneStr == null || timeZoneStr.trim().length() == 0) {
timeZoneStr = SaturnConstants.TIME_ZONE_ID_DEFAULT;
}
result.setTimeZone(timeZoneStr);
TimeZone timeZone = TimeZone.getTimeZone(timeZoneStr);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(timeZone);
String lastBeginTime = curatorFrameworkOp.getData(JobNodePath.getExecutionNodePath(jobName, item, "lastBeginTime"));
result.setLastBeginTime(null == lastBeginTime ? null : sdf.format(new Date(Long.parseLong(lastBeginTime))));
String nextFireTime = curatorFrameworkOp.getData(JobNodePath.getExecutionNodePath(jobName, item, "nextFireTime"));
result.setNextFireTime(null == nextFireTime ? null : sdf.format(new Date(Long.parseLong(nextFireTime))));
String lastCompleteTime = curatorFrameworkOp.getData(JobNodePath.getExecutionNodePath(jobName, item, "lastCompleteTime"));
if (lastCompleteTime != null) {
long lastCompleteTimeLong = Long.parseLong(lastCompleteTime);
if (lastBeginTime == null) {
result.setLastCompleteTime(sdf.format(new Date(lastCompleteTimeLong)));
} else {
long lastBeginTimeLong = Long.parseLong(lastBeginTime);
if (lastCompleteTimeLong >= lastBeginTimeLong) {
result.setLastCompleteTime(sdf.format(new Date(lastCompleteTimeLong)));
}
}
}
if (running) {
long mtime = curatorFrameworkOp.getMtime(JobNodePath.getExecutionNodePath(jobName, item, "running"));
result.setTimeConsumed( (new Date().getTime() - mtime)/1000 );
}
return result;
}
/**
* 查找运行item的服务器IP
*
* @param item 作业分片
* @param jobName 作业名称
* @return 运行item的服务器IP
*/
private String getRunningIP(String item, String jobName) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
String runningIp = null;
String serverNodePath = JobNodePath.getServerNodePath(jobName);
if(!curatorFrameworkOp.checkExists(serverNodePath)) {
return runningIp;
}
List<String> servers = curatorFrameworkOp.getChildren(serverNodePath);
for (String server : servers) {
String sharding = curatorFrameworkOp.getData(JobNodePath.getServerNodePath(jobName, server, "sharding"));
String toFind = "";
if (Strings.isNullOrEmpty(sharding)) {
continue;
}
for (String itemKey : Splitter.on(',').split(sharding)) {
if (item.equals(itemKey)) {
toFind = itemKey;
break;
}
}
if (!Strings.isNullOrEmpty(toFind)) {
runningIp = server;
break;
}
}
return runningIp;
}
@Override
public String getJobType(String jobName) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
return curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "jobType"));
}
/**
* 查找所有$SaturnExecutors下online的executor加上preferList配置中被删除的executor
*
* @param jobName 作业名称
* @return 所有executors服务器列表:executorName(ip)
*/
@Override
public String getAllExecutors(String jobName) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
return getAllExecutors(jobName, curatorFrameworkOp);
}
@Override
public String getAllExecutors(String jobName,CuratorRepository.CuratorFrameworkOp curatorFrameworkOp) {
String executorsNodePath = SaturnExecutorsNode.getExecutorsNodePath();
if(!curatorFrameworkOp.checkExists(executorsNodePath)) {
return null;
}
StringBuilder allExecutorsBuilder = new StringBuilder();
StringBuilder offlineExecutorsBuilder = new StringBuilder();
List<String> executors = curatorFrameworkOp.getChildren(executorsNodePath);
if(executors != null && executors.size()>0){
for (String executor : executors) {
if (curatorFrameworkOp.checkExists(SaturnExecutorsNode.getExecutorTaskNodePath(executor))) {
continue;// 过滤容器中的Executor,容器资源只需要可以选择taskId即可
}
String ip = curatorFrameworkOp.getData(SaturnExecutorsNode.getExecutorIpNodePath(executor));
if(StringUtils.isNotBlank(ip)){// if ip exists, means the executor is online
allExecutorsBuilder.append(executor+"("+ip+")").append(",");
continue;
}
offlineExecutorsBuilder.append(executor+"(该executor已离线)").append(",");// if ip is not exists,means the executor is offline
}
}
StringBuilder containerTaskIdsBuilder = new StringBuilder();
String containerNodePath = ContainerNodePath.getDcosTasksNodePath();
if (curatorFrameworkOp.checkExists(containerNodePath)) {
List<String> containerTaskIds = curatorFrameworkOp.getChildren(containerNodePath);
if (!CollectionUtils.isEmpty(containerTaskIds)) {
for (String containerTaskId : containerTaskIds) {
containerTaskIdsBuilder.append(containerTaskId + "(容器资源)").append(",");
}
}
}
allExecutorsBuilder.append(containerTaskIdsBuilder.toString());
allExecutorsBuilder.append(offlineExecutorsBuilder.toString());
String preferListNodePath = JobNodePath.getConfigNodePath(jobName, "preferList");
if(curatorFrameworkOp.checkExists(preferListNodePath)) {
String preferList = curatorFrameworkOp.getData(preferListNodePath);
if(!Strings.isNullOrEmpty(preferList)){
String[] preferExecutorList = preferList.split(",");
for(String preferExecutor : preferExecutorList){
if(executors != null && !executors.contains(preferExecutor) && !preferExecutor.startsWith("@")){
allExecutorsBuilder.append(preferExecutor + "(该executor已删除)").append(",");
}
}
}
}
return allExecutorsBuilder.toString();
}
@Override
public JobMigrateInfo getJobMigrateInfo(String jobName) throws SaturnJobConsoleException {
JobMigrateInfo jobMigrateInfo = new JobMigrateInfo();
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
List<String> tasksMigrateEnabled = new ArrayList<>();
List<String> tasks = new ArrayList<>();
String dcosTasksNodePath = ContainerNodePath.getDcosTasksNodePath();
if (curatorFrameworkOp.checkExists(dcosTasksNodePath)) {
tasks = curatorFrameworkOp.getChildren(dcosTasksNodePath);
}
List<String> preferTasks = new ArrayList<>();
if (tasks != null && !tasks.isEmpty()) {
String preferListNodePath = JobNodePath.getConfigNodePath(jobName, "preferList");
if (curatorFrameworkOp.checkExists(preferListNodePath)) {
String preferList = curatorFrameworkOp.getData(preferListNodePath);
if (preferList != null) {
String[] split = preferList.split(",");
for (int i = 0; i < split.length; i++) {
String prefer = split[i].trim();
if (prefer.startsWith("@")) {
preferTasks.add(prefer.substring(1));
}
}
}
}
for (String tmp : tasks) {
if (!preferTasks.contains(tmp)) {
tasksMigrateEnabled.add(tmp);
}
}
}
jobMigrateInfo.setJobName(jobName);
jobMigrateInfo.setTasksOld(preferTasks);
jobMigrateInfo.setTasksMigrateEnabled(tasksMigrateEnabled);
return jobMigrateInfo;
}
@Override
public void migrateJobNewTask(String jobName, String taskNew) throws SaturnJobConsoleException {
try {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
String jobNodePath = SaturnExecutorsNode.getJobNodePath(jobName);
if (!curatorFrameworkOp.checkExists(jobNodePath)) {
throw new SaturnJobConsoleException("The job " + jobName + " does not exists");
}
String jobConfigPreferListNodePath = SaturnExecutorsNode.getJobConfigPreferListNodePath(jobName);
if (!curatorFrameworkOp.checkExists(jobConfigPreferListNodePath)) {
throw new SaturnJobConsoleException("The job has not set a docker task");
}
String jobConfigPreferList = curatorFrameworkOp.getData(jobConfigPreferListNodePath);
if (jobConfigPreferList == null) {
throw new SaturnJobConsoleException("The job has not set a docker task");
}
if (!jobConfigPreferList.contains("@")) {
throw new SaturnJobConsoleException("The job has not set a docker task");
}
List<String> tasks = getTasks(jobConfigPreferList);
if (tasks.isEmpty()) {
throw new SaturnJobConsoleException("The job has not set a docker task");
}
if (tasks.contains(taskNew)) {
throw new SaturnJobConsoleException("the new task is already set");
}
String dcosTaskNodePath = SaturnExecutorsNode.getDcosTaskNodePath(taskNew);
if (!curatorFrameworkOp.checkExists(dcosTaskNodePath)) {
throw new SaturnJobConsoleException("The new task does not exists");
}
// replace the old task by new task
String newJobConfigPreferList = replaceTaskInPreferList(jobConfigPreferList, taskNew);
curatorFrameworkOp.update(jobConfigPreferListNodePath, newJobConfigPreferList);
// delete and create the forceShard node
String jobConfigForceShardNodePath = SaturnExecutorsNode.getJobConfigForceShardNodePath(jobName);
curatorFrameworkOp.delete(jobConfigForceShardNodePath);
curatorFrameworkOp.create(jobConfigForceShardNodePath);
} catch (SaturnJobConsoleException e) {
throw e;
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new SaturnJobConsoleException(e);
}
}
private String replaceTaskInPreferList(String jobConfigPreferList, String task) {
String newJobConfigPreferList = "";
String[] split = jobConfigPreferList.split(",");
boolean hasReplaced = false;
for (int i = 0; i < split.length; i++) {
String tmp = split[i].trim();
if (tmp.startsWith("@")) {
newJobConfigPreferList = newJobConfigPreferList + "," + "@" + task;
} else {
newJobConfigPreferList = newJobConfigPreferList + "," + tmp;
}
}
while (newJobConfigPreferList.startsWith(",")) {
newJobConfigPreferList = newJobConfigPreferList.substring(1);
}
return newJobConfigPreferList;
}
private List<String> getTasks(String jobConfigPreferList) {
List<String> tasks = new ArrayList<>();
String[] split = jobConfigPreferList.split(",");
for (int i = 0; i < split.length; i++) {
String tmp = split[i].trim();
if (tmp.startsWith("@")) {
tasks.add(tmp.substring(1));
}
}
return tasks;
}
@Override
public boolean isJobEnabled(String jobName) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
return Boolean.valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "enabled")));
}
/**
* <blockquote><pre>
* 检查否是新版本的executor(新的域)
* 旧域:该域下必须至少有一个executor并且所有的executor都没有版本号version节点
* 新域:该域下必须至少有一个executor并且所有的executor都有版本号version节点(新版本的executor才在启动时添加了这个节点)
* 未知域:该域下没有任何executor或executor中既有新版的又有旧版的Executor
*
* @param version 指定的executor的版本
* @return 当version参数为空时:1:新域 0:旧域 -1:未知域(无法判断新旧域)
* 当version参数不为空时,说明要判断是否大于该版本,仅适用于1.1.0及其之后的版本比较:
* 2:该域下所有Executor的版本都大于等于指定的版本
* -2:该域下所有Executor的版本都小于指定的版本
* -3:Executor的版本存在大于、等于或小于指定的版本
* </pre></blockquote>
*/
public int isNewSaturn(String version) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
if(!curatorFrameworkOp.checkExists(ExecutorNodePath.getExecutorNodePath())){
return -1;
}
List<String> executors = curatorFrameworkOp.getChildren(ExecutorNodePath.getExecutorNodePath());
if(executors == null || executors.size() == 0){
return -1;
}
int oldExecutorSize = 0;
int newExecutorSize = 0;
int lessThanExecutorSize = 0;
int moreThanExecutorSize = 0;
boolean isCompareVersion = !Strings.isNullOrEmpty(version);
for(String executor : executors){
String executorVersionPath = ExecutorNodePath.getExecutorNodePath(executor, "version");
if (!curatorFrameworkOp.checkExists(executorVersionPath)) {
++oldExecutorSize;
continue;
}
++newExecutorSize;
if(isCompareVersion){// 1.1.0及之后的版本比较,1.1.0及其以后的executor才有version节点
String executorVersion = curatorFrameworkOp.getData(executorVersionPath);
try{
if(Strings.isNullOrEmpty(executorVersion)){
++lessThanExecutorSize;// 如果取到的版本号为空串,默认认为是比当前指定版本要低
continue;
}
int compareResult = compareVersion(executorVersion,version);
if(compareResult < 0){// 比指定版本小
++lessThanExecutorSize;
continue;
}
++moreThanExecutorSize;// 大于等于指定版本
}catch(NumberFormatException e){
++lessThanExecutorSize;// 如果遇到非数字(非1.1.x)的版本号,如saturn-dev,默认认为是比当前指定版本要低
}
}
}
int executorSize = executors.size();
if(oldExecutorSize == executorSize){// 先判断如果是全是旧版本的话直接返回
return 0;
}
if(isCompareVersion){// 新版本才存在需要比较版本号的情况
if(lessThanExecutorSize > 0 && moreThanExecutorSize > 0){
return -3;
}
if(lessThanExecutorSize == executorSize){
return -2;
}
if(moreThanExecutorSize == executorSize){
return 2;
}
return -1;// 该域下的executor有些有version节点,有些没有version节点,无法判断
}
if(newExecutorSize == executorSize){
return 1;
}
return -1;
}
/**
* 比较两个executor的版本,以“.”分割成数组,从第一个数开始逐一比较
*
* <p>Examples:
* <blockquote><pre>
* 1.0.1 < 1.1.0
* 1.0.1 < 1.0.10
* 1.0.9 < 1.0.10
* 1.0.1 = 1.0.1
* 2.0.0 > 1.1.9
* 1.0.1.0 > 1.0.0.10
* </blockquote></pre>
*
* @param version1 executor1的版本
* @param version2 executor2的版本
* @return 1:version1的版本大于version2的版本
* 0:version1的版本等于version2的版本
* -1:version1的版本小于version2的版本
*/
private int compareVersion(String version1, String version2) throws NumberFormatException{
String[] version1Arr = version1.split("\\.");
String[] version2Arr = version2.split("\\.");
int versionLength = Math.min(version1Arr.length, version2Arr.length);
for(int i=0;i<versionLength;i++){
int v1 = Integer.parseInt(version1Arr[i]);
int v2 = Integer.parseInt(version2Arr[i]);
if(v1 > v2){// 只要比较到某一位v1大于v2,就认为version1比version2大,如1.1.0和1.0.1.1的第二位就可以看出1.1.0>1.0.1.1
return 1;
}
if(v1 < v2){
return -1;
}
}
if(version1Arr.length == version2Arr.length){// 1.0.1 = 1.0.1
return 0;
}
if(version1Arr.length > version2Arr.length){// 1.0.0.1 > 1.0.0
return 1;
}
return -1;// 1.0.0 < 1.0.0.1
}
@Override
public String formatTimeByJobTimeZone(String jobName, Long time) {
if(time != null) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
String timeZoneStr = getTimeZone(jobName, curatorFrameworkOp);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone(timeZoneStr));
return timeZoneStr + " " + sdf.format(new Date(time));
}
return null;
}
private String getTimeZone(String jobName, CuratorRepository.CuratorFrameworkOp curatorFrameworkOp) {
String timeZoneStr = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "timeZone"));
if(timeZoneStr == null || timeZoneStr.trim().length() == 0) {
timeZoneStr = SaturnConstants.TIME_ZONE_ID_DEFAULT;
}
return timeZoneStr;
}
@Override
public Long calculateJobNextTime(String jobName) {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
try {
// 计算异常作业,根据$Jobs/jobName/execution/item/nextFireTime,如果小于当前时间且作业不在running,则为异常
// 只有java/shell作业有cron
String jobType = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "jobType"));
if (JobType.JAVA_JOB.name().equals(jobType) || JobType.SHELL_JOB.name().equals(jobType)) {
// enabled 的作业才需要判断
String enabledPath = JobNodePath.getConfigNodePath(jobName, "enabled");
if (Boolean.valueOf(curatorFrameworkOp.getData(enabledPath))) {
String enabledReportPath = JobNodePath.getConfigNodePath(jobName, "enabledReport");
String enabledReportVal = curatorFrameworkOp.getData(enabledReportPath);
// 开启上报运行信息
if (enabledReportVal == null || "true".equals(enabledReportVal)) {
long nextFireTimeAfterThis = 0l;
String executionRootpath = JobNodePath.getExecutionNodePath(jobName);
// 有execution节点
if (curatorFrameworkOp.checkExists(executionRootpath)) {
List<String> items = curatorFrameworkOp.getChildren(executionRootpath);
// 有分片
if (items != null && !items.isEmpty()) {
for (String itemStr : items) {
// 针对stock-update域的不上报节点信息但又有分片残留的情况
List<String> itemChildren = curatorFrameworkOp.getChildren(JobNodePath.getExecutionItemNodePath(jobName, itemStr));
if (itemChildren.size() == 2) {
return null;
} else {
String runningNodePath = JobNodePath.getExecutionNodePath(jobName, itemStr, "running");
boolean isItemRunning = curatorFrameworkOp.checkExists(runningNodePath);
if (isItemRunning) {
try { // 以防节点不存在
return curatorFrameworkOp.getMtime(runningNodePath);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
String completedPath = JobNodePath.getExecutionNodePath(jobName, itemStr, "completed");
boolean isItemCompleted = curatorFrameworkOp.checkExists(completedPath);
if (isItemCompleted) {
long thisCompleteMtime = curatorFrameworkOp.getMtime(completedPath);
if (thisCompleteMtime > nextFireTimeAfterThis) {
nextFireTimeAfterThis = thisCompleteMtime;
}
}
}
}
}
}
// 对比enabled's mtime 和 completed's mtime
long enabledMtime = curatorFrameworkOp.getMtime(enabledPath);
if (enabledMtime > nextFireTimeAfterThis) {
nextFireTimeAfterThis = enabledMtime;
}
return getNextFireTimeAfterSpecifiedTimeExcludePausePeriod(nextFireTimeAfterThis, jobName, curatorFrameworkOp);
} else {
// 关闭上报视为正常
return null;
}
}
return null;
}
// 非java/shell job视为正常
return null;
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
/**
* 该时间是否在作业暂停时间段范围内。
* <p>特别的,无论pausePeriodDate,还是pausePeriodTime,如果解析发生异常,则忽略该节点,视为没有配置该日期或时分段。
*
* @return 该时间是否在作业暂停时间段范围内。
*/
private static boolean isInPausePeriod(Date date, String pausePeriodDate, String pausePeriodTime, TimeZone timeZone) {
Calendar calendar = Calendar.getInstance(timeZone);
calendar.setTime(date);
int M = calendar.get(Calendar.MONTH) + 1; // Calendar.MONTH begin from 0.
int d = calendar.get(Calendar.DAY_OF_MONTH);
int h = calendar.get(Calendar.HOUR_OF_DAY);
int m = calendar.get(Calendar.MINUTE);
boolean dateIn = false;
boolean pausePeriodDateIsEmpty = (pausePeriodDate==null || pausePeriodDate.trim().isEmpty());
if(!pausePeriodDateIsEmpty){
String[] periodsDate = pausePeriodDate.split(",");
if (periodsDate != null) {
for (String period : periodsDate) {
String[] tmp = period.trim().split("-");
if (tmp != null && tmp.length == 2) {
String left = tmp[0].trim();
String right = tmp[1].trim();
String[] MdLeft = left.split("/");
String[] MdRight = right.split("/");
if (MdLeft != null && MdLeft.length == 2 && MdRight != null && MdRight.length == 2) {
try {
int MLeft = Integer.parseInt(MdLeft[0]);
int dLeft = Integer.parseInt(MdLeft[1]);
int MRight = Integer.parseInt(MdRight[0]);
int dRight = Integer.parseInt(MdRight[1]);
dateIn = (M > MLeft || M == MLeft && d >= dLeft) && (M < MRight || M == MRight && d <= dRight);//NOSONAR
if (dateIn) {
break;
}
} catch (NumberFormatException e) {
dateIn = false;
break;
}
} else {
dateIn = false;
break;
}
} else {
dateIn = false;
break;
}
}
}
}
boolean timeIn = false;
boolean pausePeriodTimeIsEmpty = (pausePeriodTime==null||pausePeriodTime.trim().isEmpty());
if(!pausePeriodTimeIsEmpty){
String[] periodsTime = pausePeriodTime.split(",");
if (periodsTime != null) {
for (String period : periodsTime) {
String[] tmp = period.trim().split("-");
if (tmp != null && tmp.length == 2) {
String left = tmp[0].trim();
String right = tmp[1].trim();
String[] hmLeft = left.split(":");
String[] hmRight = right.split(":");
if (hmLeft != null && hmLeft.length == 2 && hmRight != null && hmRight.length == 2) {
try {
int hLeft = Integer.parseInt(hmLeft[0]);
int mLeft = Integer.parseInt(hmLeft[1]);
int hRight = Integer.parseInt(hmRight[0]);
int mRight = Integer.parseInt(hmRight[1]);
timeIn = (h > hLeft || h == hLeft && m >= mLeft) && (h < hRight || h == hRight && m <= mRight);//NOSONAR
if (timeIn) {
break;
}
} catch (NumberFormatException e) {
timeIn = false;
break;
}
} else {
timeIn = false;
break;
}
} else {
timeIn = false;
break;
}
}
}
}
if(pausePeriodDateIsEmpty) {
if(pausePeriodTimeIsEmpty) {
return false;
} else {
return timeIn;
}
} else {
if(pausePeriodTimeIsEmpty) {
return dateIn;
} else {
return dateIn && timeIn;
}
}
}
@Override
public Long getNextFireTimeAfterSpecifiedTimeExcludePausePeriod(long nextFireTimeAfterThis, String jobName, CuratorRepository.CuratorFrameworkOp curatorFrameworkOp) {
String cronPath = JobNodePath.getConfigNodePath(jobName, "cron");
String cronVal = curatorFrameworkOp.getData(cronPath);
CronExpression cronExpression = null;
try {
cronExpression = new CronExpression(cronVal);
} catch (ParseException e) {
log.error(e.getMessage(), e);
return null;
}
String timeZoneStr = getTimeZone(jobName, curatorFrameworkOp);
TimeZone timeZone = TimeZone.getTimeZone(timeZoneStr);
cronExpression.setTimeZone(timeZone);
Date nextFireTime = cronExpression.getTimeAfter(new Date(nextFireTimeAfterThis));
String pausePeriodDatePath = JobNodePath.getConfigNodePath(jobName, "pausePeriodDate");
String pausePeriodDate = curatorFrameworkOp.getData(pausePeriodDatePath);
String pausePeriodTimePath = JobNodePath.getConfigNodePath(jobName, "pausePeriodTime");
String pausePeriodTime = curatorFrameworkOp.getData(pausePeriodTimePath);
while (nextFireTime != null && isInPausePeriod(nextFireTime, pausePeriodDate, pausePeriodTime, timeZone)) {
nextFireTime = cronExpression.getTimeAfter(nextFireTime);
}
if (null == nextFireTime) {
return null;
}
return nextFireTime.getTime();
}
@Override
public List<String> getAllJobGroups() {
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
List<String> jobNames = new ArrayList<>();
try {
jobNames = getAllUnSystemJobs(curatorFrameworkOp);
} catch (SaturnJobConsoleException e) {
log.error(e.getMessage(), e);
}
List<String> result = new ArrayList<>(jobNames.size());
for (String jobName : jobNames) {
String groups = curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(jobName, "groups"));
if(Strings.isNullOrEmpty(groups) || result.contains(groups)){
continue;
}
result.add(groups);
}
return result;
}
@Override
public JobMigrateInfo getAllJobMigrateInfo()
throws SaturnJobConsoleException {
JobMigrateInfo jobMigrateInfo = new JobMigrateInfo();
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
List<String> tasksMigrateEnabled = new ArrayList<>();
List<String> tasks = new ArrayList<>();
String dcosTasksNodePath = ContainerNodePath.getDcosTasksNodePath();
if (curatorFrameworkOp.checkExists(dcosTasksNodePath)) {
tasks = curatorFrameworkOp.getChildren(dcosTasksNodePath);
}
if (tasks != null && !tasks.isEmpty()) {
for (String tmp : tasks) {
tasksMigrateEnabled.add(tmp);
}
}
jobMigrateInfo.setTasksMigrateEnabled(tasksMigrateEnabled);
return jobMigrateInfo;
}
@Override
public void batchMigrateJobNewTask(String jobNames, String taskNew)
throws SaturnJobConsoleException {
for (String jobName : jobNames.split(",")) {
List<String> preferTasks = getPreferTasksByJobName(jobName);
if(preferTasks.size() == 0){
throw new SaturnJobConsoleException(jobName + ":The job has not set a docker task");
}
if(preferTasks.contains(taskNew)){
throw new SaturnJobConsoleException(jobName + ":The taskNew is equals to current task");
}
}
for (String jobName : jobNames.split(",")) {
try{
this.migrateJobNewTask(jobName, taskNew);
}catch(SaturnJobConsoleException e){
throw new SaturnJobConsoleException(jobName + ":" + e.getMessage());
}
}
}
private List<String> getPreferTasksByJobName(String jobName){
CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = curatorRepository.inSessionClient();
List<String> tasks = new ArrayList<>();
String dcosTasksNodePath = ContainerNodePath.getDcosTasksNodePath();
if (curatorFrameworkOp.checkExists(dcosTasksNodePath)) {
tasks = curatorFrameworkOp.getChildren(dcosTasksNodePath);
}
List<String> preferTasks = new ArrayList<>();
if (tasks != null && !tasks.isEmpty()) {
String preferListNodePath = JobNodePath.getConfigNodePath(jobName, "preferList");
if (curatorFrameworkOp.checkExists(preferListNodePath)) {
String preferList = curatorFrameworkOp.getData(preferListNodePath);
if (preferList != null) {
String[] split = preferList.split(",");
for (int i = 0; i < split.length; i++) {
String prefer = split[i].trim();
if (prefer.startsWith("@")) {
preferTasks.add(prefer.substring(1));
}
}
}
}
}
return preferTasks;
}
}