package com.hujiang.juice.rest.service;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.hujiang.jooq.juice.tables.pojos.JuiceTask;
import com.hujiang.juice.common.error.CommonStatusCode;
import com.hujiang.juice.common.error.ErrorCode;
import com.hujiang.juice.common.exception.RestException;
import com.hujiang.juice.common.model.TaskManagement;
import com.hujiang.juice.common.utils.cache.CacheUtils;
import com.hujiang.juice.common.utils.generator.IdGenerator;
import com.hujiang.juice.common.vo.SubmitTask;
import com.hujiang.juice.common.vo.TaskKill;
import com.hujiang.juice.common.vo.TaskResult;
import com.hujiang.juice.common.vo.TaskReconcile;
import com.hujiang.juice.common.utils.db.DaoUtils;
import com.hujiang.juice.rest.config.CachesBizConfig;
import com.hujiang.juice.rest.utils.TaskUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import static com.hujiang.juice.common.config.COMMON.KILL;
import static com.hujiang.juice.common.config.COMMON.RECONCILE;
/**
* Created by xujia on 16/12/5.
*/
@Slf4j
@Data
@Service
public class RestService {
@Autowired
private DaoUtils daoUtils;
@Autowired
private CacheUtils cacheUtils;
@Autowired
private CachesBizConfig cachesBizConfig;
private Gson gson = new Gson();
private static final String POINT = ".";
public long submits(SubmitTask object, String tenantId) {
// set run mode
object.setRunMode(TaskUtils.checkRunMode(object));
// generate taskId
object.setTaskId(IdGenerator.nextId());
log.info("TaskId --> " + object.getTaskId() + ", TaskName : " + object.getTaskName());
// submit(record in db and submit in redis)
daoUtils.getContext().transaction(
configuration -> {
String commands = "";
String dockerImage = "";
if (object.getRunMode() == SubmitTask.RunModel.CONTAINER) {
dockerImage = object.getContainer().getDocker().getImage();
} else {
commands = object.getCommands();
}
boolean isInsert = daoUtils.submit(configuration, object.getTaskId(), tenantId, object.getCallbackUrl(), object.getTaskName(), dockerImage, commands);
if (isInsert) {
cacheUtils.pushToQueue(cachesBizConfig.getTaskQueue(), gson.toJson(object.toTask()));
}
}
);
return object.getTaskId();
}
public TaskKill kills(String tenantId, long taskId) {
JuiceTask task = daoUtils.queryTask(tenantId, taskId);
if (null == task) {
throw new RestException(CommonStatusCode.QUERY_RECORD_EMPTY.getStatus(), "task not exist to kill!");
}
if (task.getTaskStatus() > TaskResult.Result.RUNNING.getType()) {
return new TaskKill(false, task.getTaskStatus(), task.getMessage());
}
TaskManagement taskManagement = new TaskManagement(Lists.newCopyOnWriteArrayList(), KILL);
TaskManagement.TaskAgentRel taskAgentRel = new TaskManagement.TaskAgentRel(task.getTaskId(), task.getTaskName(), task.getAgentId());
taskManagement.getTaskAgentRels().add(taskAgentRel);
//
// String key = cachesBizConfig.getKillKeyPrefix() + POINT + taskId;
// cacheUtils.setExpired(key, "1", cachesBizConfig.getExpiredSeconds());
cacheUtils.pushToQueue(cachesBizConfig.getManagementQueue(), gson.toJson(taskManagement));
return new TaskKill(true, task.getTaskStatus(), "juice accept kill task command");
}
public List<JuiceTask> querys(String tenantId, List<Long> taskId) {
return daoUtils.queryTasks(tenantId, taskId);
}
public TaskReconcile reconciles(String tenantId, List<Long> taskIds) {
List<JuiceTask> tasks = daoUtils.queryTasks(tenantId, taskIds);
Map<Long, TaskReconcile.Reconcile> reconcileMap = getTaskReconcile(taskIds);
TaskManagement taskManagement = new TaskManagement(Lists.newCopyOnWriteArrayList(), RECONCILE);
tasks.stream().parallel().forEach(t -> {
String value = t.getAgentId();
boolean isReconciled = false;
String message = "";
TaskReconcile.Reconcile reconcile = reconcileMap.get(t.getTaskId());
if (null == reconcile) {
String error = "taskId not matched with database record, taskId: " + t.getTaskId();
log.warn(error);
throw new RestException(ErrorCode.OBJECT_NOT_EQUAL_ERROR.getCode(), error);
} else if (!t.getTaskStatus().equals(TaskResult.Result.RUNNING.getType())) {
message = "not reconcile due to terminal task status : " + TaskResult.Result.getName(t.getTaskStatus());
} else if (StringUtils.isBlank(value)) {
reconcile.setReconciled(false);
daoUtils.finishTask(t.getTaskId(), TaskResult.Result.EXPIRED.getType(), "task expired");
message = "not reconcile due to terminal task status : " + TaskResult.Result.EXPIRED.name();
} else {
TaskManagement.TaskAgentRel taskAgentRel = new TaskManagement.TaskAgentRel(t.getTaskId(), t.getTaskName(), value);
taskManagement.getTaskAgentRels().add(taskAgentRel);
isReconciled = true;
message = "reconcile task";
}
reconcile.setTaskId(t.getTaskId());
reconcile.setReconciled(isReconciled);
reconcile.setMessage(message);
});
int reconcileCount = taskManagement.getTaskAgentRels().size();
if (reconcileCount > 0) {
cacheUtils.pushToQueue(cachesBizConfig.getManagementQueue(), gson.toJson(taskManagement));
}
return new TaskReconcile(taskIds.size(), reconcileCount, mapsToLists(reconcileMap));
}
private Map<Long, TaskReconcile.Reconcile> getTaskReconcile(List<Long> tasks) {
Map<Long, TaskReconcile.Reconcile> reconcileMap = Maps.newConcurrentMap();
tasks.stream().parallel().forEach(v -> {
reconcileMap.put(v, new TaskReconcile.Reconcile(v, false, "invalid taskId"));
});
return reconcileMap;
}
private List<TaskReconcile.Reconcile> mapsToLists(Map<Long, TaskReconcile.Reconcile> map) {
final List<TaskReconcile.Reconcile> reconciles = Lists.newCopyOnWriteArrayList();
map.entrySet().parallelStream().forEach(
v -> {
reconciles.add(v.getValue());
}
);
return reconciles;
}
}