/*
* Copyright 1999-2015 dangdang.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.dangdang.ddframe.job.cloud.scheduler.mesos;
import com.dangdang.ddframe.job.cloud.scheduler.config.app.CloudAppConfiguration;
import com.dangdang.ddframe.job.cloud.scheduler.config.app.CloudAppConfigurationService;
import com.dangdang.ddframe.job.cloud.scheduler.config.job.CloudJobConfiguration;
import com.dangdang.ddframe.job.cloud.scheduler.config.job.CloudJobConfigurationService;
import com.dangdang.ddframe.job.cloud.scheduler.config.job.CloudJobExecutionType;
import com.dangdang.ddframe.job.cloud.scheduler.context.JobContext;
import com.dangdang.ddframe.job.cloud.scheduler.state.disable.app.DisableAppService;
import com.dangdang.ddframe.job.cloud.scheduler.state.disable.job.DisableJobService;
import com.dangdang.ddframe.job.cloud.scheduler.state.failover.FailoverService;
import com.dangdang.ddframe.job.cloud.scheduler.state.failover.FailoverTaskInfo;
import com.dangdang.ddframe.job.cloud.scheduler.state.ready.ReadyService;
import com.dangdang.ddframe.job.cloud.scheduler.state.running.RunningService;
import com.dangdang.ddframe.job.context.ExecutionType;
import com.dangdang.ddframe.job.context.TaskContext;
import com.dangdang.ddframe.job.context.TaskContext.MetaInfo;
import com.dangdang.ddframe.job.reg.base.CoordinatorRegistryCenter;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 为Mesos提供的门面服务.
*
* @author zhangliang
* @author caohao
*/
@Slf4j
public final class FacadeService {
private final CloudAppConfigurationService appConfigService;
private final CloudJobConfigurationService jobConfigService;
private final ReadyService readyService;
private final RunningService runningService;
private final FailoverService failoverService;
private final DisableAppService disableAppService;
private final DisableJobService disableJobService;
public FacadeService(final CoordinatorRegistryCenter regCenter) {
appConfigService = new CloudAppConfigurationService(regCenter);
jobConfigService = new CloudJobConfigurationService(regCenter);
readyService = new ReadyService(regCenter);
runningService = new RunningService(regCenter);
failoverService = new FailoverService(regCenter);
disableAppService = new DisableAppService(regCenter);
disableJobService = new DisableJobService(regCenter);
}
/**
* 启动门面服务.
*/
public void start() {
log.info("Elastic Job: Start facade service");
runningService.start();
}
/**
* 获取有资格运行的作业.
*
* @return 作业上下文集合
*/
public Collection<JobContext> getEligibleJobContext() {
Collection<JobContext> failoverJobContexts = failoverService.getAllEligibleJobContexts();
Collection<JobContext> readyJobContexts = readyService.getAllEligibleJobContexts(failoverJobContexts);
Collection<JobContext> result = new ArrayList<>(failoverJobContexts.size() + readyJobContexts.size());
result.addAll(failoverJobContexts);
result.addAll(readyJobContexts);
return result;
}
/**
* 从队列中删除已运行的作业.
*
* @param taskContexts 任务上下文集合
*/
public void removeLaunchTasksFromQueue(final List<TaskContext> taskContexts) {
List<TaskContext> failoverTaskContexts = new ArrayList<>(taskContexts.size());
Collection<String> readyJobNames = new HashSet<>(taskContexts.size(), 1);
for (TaskContext each : taskContexts) {
switch (each.getType()) {
case FAILOVER:
failoverTaskContexts.add(each);
break;
case READY:
readyJobNames.add(each.getMetaInfo().getJobName());
break;
default:
break;
}
}
failoverService.remove(Lists.transform(failoverTaskContexts, new Function<TaskContext, TaskContext.MetaInfo>() {
@Override
public TaskContext.MetaInfo apply(final TaskContext input) {
return input.getMetaInfo();
}
}));
readyService.remove(readyJobNames);
}
/**
* 将任务运行时上下文放入运行时队列.
*
* @param taskContext 任务运行时上下文
*/
public void addRunning(final TaskContext taskContext) {
runningService.add(taskContext);
}
/**
* 更新常驻作业运行状态.
*
* @param taskContext 任务运行时上下文
* @param isIdle 是否空闲
*/
public void updateDaemonStatus(final TaskContext taskContext, final boolean isIdle) {
runningService.updateIdle(taskContext, isIdle);
}
/**
* 将任务从运行时队列删除.
*
* @param taskContext 任务运行时上下文
*/
public void removeRunning(final TaskContext taskContext) {
runningService.remove(taskContext);
}
/**
* 记录失效转移队列.
*
* @param taskContext 任务上下文
*/
public void recordFailoverTask(final TaskContext taskContext) {
Optional<CloudJobConfiguration> jobConfigOptional = jobConfigService.load(taskContext.getMetaInfo().getJobName());
if (!jobConfigOptional.isPresent()) {
return;
}
CloudJobConfiguration jobConfig = jobConfigOptional.get();
if (jobConfig.getTypeConfig().getCoreConfig().isFailover() || CloudJobExecutionType.DAEMON == jobConfig.getJobExecutionType()) {
failoverService.add(taskContext);
}
}
/**
* 将瞬时作业放入待执行队列.
*
* @param jobName 作业名称
*/
public void addTransient(final String jobName) {
readyService.addTransient(jobName);
}
/**
* 根据作业名称获取云作业配置.
*
* @param jobName 作业名称
* @return 云作业配置
*/
public Optional<CloudJobConfiguration> load(final String jobName) {
return jobConfigService.load(jobName);
}
/**
* 根据作业应用名称获取云作业应用配置.
*
* @param appName 作业应用名称
* @return 云作业应用配置
*/
public Optional<CloudAppConfiguration> loadAppConfig(final String appName) {
return appConfigService.load(appName);
}
/**
* 根据作业元信息获取失效转移作业Id.
*
* @param metaInfo 作业元信息
* @return 失效转移作业Id
*/
public Optional<String> getFailoverTaskId(final MetaInfo metaInfo) {
return failoverService.getTaskId(metaInfo);
}
/**
* 将常驻作业放入待执行队列.
*
* @param jobName 作业名称
*/
public void addDaemonJobToReadyQueue(final String jobName) {
readyService.addDaemon(jobName);
}
/**
* 根据作业执行类型判断作业是否在运行.
*
* <p>READY类型的作业为整体, 任意一片运行都视为作业运行. FAILOVER则仅以当前分片运行为运行依据.</p>
*
* @param taskContext 任务运行时上下文
* @return 作业是否在运行
*/
public boolean isRunning(final TaskContext taskContext) {
return ExecutionType.FAILOVER != taskContext.getType() && !runningService.getRunningTasks(taskContext.getMetaInfo().getJobName()).isEmpty()
|| ExecutionType.FAILOVER == taskContext.getType() && runningService.isTaskRunning(taskContext.getMetaInfo());
}
/**
* 添加任务主键和主机名称的映射.
*
* @param taskId 任务主键
* @param hostname 主机名称
*/
public void addMapping(final String taskId, final String hostname) {
runningService.addMapping(taskId, hostname);
}
/**
* 根据任务主键获取主机名称并清除该任务.
*
* @param taskId 任务主键
* @return 删除任务的主机名称
*/
public String popMapping(final String taskId) {
return runningService.popMapping(taskId);
}
/**
* 获取待运行的全部任务.
*
* @return 待运行的全部任务
*/
public Map<String, Integer> getAllReadyTasks() {
return readyService.getAllReadyTasks();
}
/**
* 获取所有运行中的任务.
*
* @return 运行中任务集合
*/
public Map<String, Set<TaskContext>> getAllRunningTasks() {
return runningService.getAllRunningTasks();
}
/**
* 获取待失效转移的全部任务.
*
* @return 待失效转移的全部任务
*/
public Map<String, Collection<FailoverTaskInfo>> getAllFailoverTasks() {
return failoverService.getAllFailoverTasks();
}
/**
* 判断作业是否被禁用.
*
* @param jobName 作业名称
* @return 作业是否被禁用
*/
public boolean isJobDisabled(final String jobName) {
Optional<CloudJobConfiguration> jobConfiguration = jobConfigService.load(jobName);
return !jobConfiguration.isPresent() || disableAppService.isDisabled(jobConfiguration.get().getAppName()) || disableJobService.isDisabled(jobName);
}
/**
* 将作业移出禁用队列.
*
* @param jobName 作业名称
*/
public void enableJob(final String jobName) {
disableJobService.remove(jobName);
}
/**
* 将作业放入禁用队列.
*
* @param jobName 作业名称
*/
public void disableJob(final String jobName) {
disableJobService.add(jobName);
}
/**
* 停止门面服务.
*/
public void stop() {
log.info("Elastic Job: Stop facade service");
// TODO 停止作业调度
runningService.clear();
}
}