Unverified Commit 4aed0227 authored by aiwenmo's avatar aiwenmo Committed by GitHub

[Feature-1110][admin,web,core,process] Add process manager and remove root log (#1111)

Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>
parent 0ee0a855
...@@ -199,11 +199,14 @@ ...@@ -199,11 +199,14 @@
<artifactId>dlink-client-hadoop</artifactId> <artifactId>dlink-client-hadoop</artifactId>
<scope>${scope.runtime}</scope> <scope>${scope.runtime}</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.dlink</groupId> <groupId>com.dlink</groupId>
<artifactId>dlink-scheduler</artifactId> <artifactId>dlink-scheduler</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.dlink</groupId>
<artifactId>dlink-process</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
package com.dlink.controller;
import com.dlink.common.result.ProTableResult;
import com.dlink.process.model.ProcessEntity;
import com.dlink.service.ProcessService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* ProcessController
*
* @author wenmo
* @since 2022/10/16 22:53
*/
@RestController
@RequestMapping("/api/process")
public class ProcessController {
@Autowired
private ProcessService processService;
@GetMapping("/listAllProcess")
public ProTableResult<ProcessEntity> listAllProcess(@RequestParam boolean active) {
List<ProcessEntity> processEntities = processService.listAllProcess(active);
return ProTableResult.<ProcessEntity>builder().success(true).data(processEntities).build();
}
}
...@@ -46,6 +46,7 @@ public class FlinkJobTaskPool extends AbstractPool<JobInfoDetail> { ...@@ -46,6 +46,7 @@ public class FlinkJobTaskPool extends AbstractPool<JobInfoDetail> {
return flinkJobTaskEntityMap; return flinkJobTaskEntityMap;
} }
@Override
public void refresh(JobInfoDetail entity) { public void refresh(JobInfoDetail entity) {
entity.refresh(); entity.refresh();
} }
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
package com.dlink.service;
import com.dlink.process.model.ProcessEntity;
import java.util.List;
/**
* ProcessService
*
* @author wenmo
* @since 2022/10/16 22:05
*/
public interface ProcessService {
List<ProcessEntity> listAllProcess(boolean active);
}
...@@ -19,12 +19,11 @@ ...@@ -19,12 +19,11 @@
package com.dlink.service; package com.dlink.service;
import com.dlink.job.JobConfig;
/** /**
* @author ZackYoung * @author ZackYoung
* @since 0.6.8 * @since 0.6.8
*/ */
public interface UDFService { public interface UDFService {
void initUDF(JobConfig config, String statement);
String[] initUDF(String statement);
} }
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
package com.dlink.service.impl;
import com.dlink.process.model.ProcessEntity;
import com.dlink.process.pool.ProcessPool;
import com.dlink.service.ProcessService;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
/**
* ProcessServiceImpl
*
* @author wenmo
* @since 2022/10/16 22:45
*/
@Service
public class ProcessServiceImpl implements ProcessService {
@Override
public List<ProcessEntity> listAllProcess(boolean active) {
Map<String, ProcessEntity> processEntityMap = ProcessPool.getInstance().getMap();
if (active) {
return processEntityMap.values().stream().filter(x -> x.isActiveProcess())
.sorted(Comparator.comparing(ProcessEntity::getStartTime).reversed()).collect(Collectors.toList());
}
return processEntityMap.values().stream().sorted(Comparator.comparing(ProcessEntity::getStartTime).reversed())
.collect(Collectors.toList());
}
}
...@@ -21,9 +21,10 @@ package com.dlink.service.impl; ...@@ -21,9 +21,10 @@ package com.dlink.service.impl;
import com.dlink.constant.PathConstant; import com.dlink.constant.PathConstant;
import com.dlink.gateway.GatewayType; import com.dlink.gateway.GatewayType;
import com.dlink.job.JobConfig;
import com.dlink.job.JobManager; import com.dlink.job.JobManager;
import com.dlink.model.Task; import com.dlink.model.Task;
import com.dlink.process.context.ProcessContextHolder;
import com.dlink.process.model.ProcessEntity;
import com.dlink.service.TaskService; import com.dlink.service.TaskService;
import com.dlink.service.UDFService; import com.dlink.service.UDFService;
import com.dlink.utils.UDFUtil; import com.dlink.utils.UDFUtil;
...@@ -40,29 +41,31 @@ import cn.hutool.core.collection.CollUtil; ...@@ -40,29 +41,31 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Opt; import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
/** /**
* @author ZackYoung * @author ZackYoung
* @since 0.6.8 * @since 0.6.8
*/ */
@Service @Service
public class UDFServiceImpl implements UDFService { public class UDFServiceImpl implements UDFService {
/** /**
* 网关类型 map * 网关类型 map
* 快速获取 session 与 application 等类型,为了减少判断 * 快速获取 session 与 application 等类型,为了减少判断
*/ */
private static final Map<String, List<GatewayType>> GATEWAY_TYPE_MAP = MapUtil private static final Map<String, List<GatewayType>> GATEWAY_TYPE_MAP = MapUtil
.builder("session", Arrays.asList(GatewayType.YARN_SESSION, GatewayType.KUBERNETES_SESSION, GatewayType.STANDALONE)) .builder("session",
Arrays.asList(GatewayType.YARN_SESSION, GatewayType.KUBERNETES_SESSION, GatewayType.STANDALONE))
.build(); .build();
@Resource @Resource
TaskService taskService; TaskService taskService;
@Override @Override
public void initUDF(JobConfig config, String statement) { public String[] initUDF(String statement) {
ProcessEntity process = ProcessContextHolder.getProcess();
process.info("Initializing Flink UDF...Start");
Opt<String> udfJarPath = Opt.empty(); Opt<String> udfJarPath = Opt.empty();
List<String> udfClassNameList = UDFUtil.getUDFClassName(statement);
List<String> udfClassNameList = JobManager.getUDFClassName(statement);
List<String> codeList = CollUtil.map(udfClassNameList, x -> { List<String> codeList = CollUtil.map(udfClassNameList, x -> {
Task task = taskService.getUDFByClassName(x); Task task = taskService.getUDFByClassName(x);
JobManager.initMustSuccessUDF(x, task.getStatement()); JobManager.initMustSuccessUDF(x, task.getStatement());
...@@ -71,7 +74,11 @@ public class UDFServiceImpl implements UDFService { ...@@ -71,7 +74,11 @@ public class UDFServiceImpl implements UDFService {
if (codeList.size() > 0) { if (codeList.size() > 0) {
udfJarPath = Opt.ofBlankAble(UDFUtil.getUdfNameAndBuildJar(codeList)); udfJarPath = Opt.ofBlankAble(UDFUtil.getUdfNameAndBuildJar(codeList));
} }
process.info("Initializing Flink UDF...Finish");
udfJarPath.ifPresent(jarPath -> config.setJarFiles(new String[]{PathConstant.UDF_PATH + jarPath})); if (udfJarPath.isPresent()) {
return new String[]{PathConstant.UDF_PATH + udfJarPath.get()};
} else {
return new String[0];
}
} }
} }
...@@ -15,18 +15,16 @@ ...@@ -15,18 +15,16 @@
~ See the License for the specific language governing permissions and ~ See the License for the specific language governing permissions and
~ limitations under the License. ~ limitations under the License.
--> -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>dlink</artifactId>
<groupId>com.dlink</groupId> <groupId>com.dlink</groupId>
<artifactId>dlink</artifactId>
<version>0.6.8-SNAPSHOT</version> <version>0.6.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>dlink-core</artifactId> <artifactId>dlink-core</artifactId>
<packaging>jar</packaging>
<properties> <properties>
<java.version>1.8</java.version> <java.version>1.8</java.version>
...@@ -176,5 +174,9 @@ ...@@ -176,5 +174,9 @@
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId> <artifactId>druid-spring-boot-starter</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.dlink</groupId>
<artifactId>dlink-process</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>
...@@ -19,13 +19,13 @@ ...@@ -19,13 +19,13 @@
package com.dlink.utils; package com.dlink.utils;
import static com.dlink.constant.PathConstant.UDF_JAR_RULE;
import static com.dlink.constant.PathConstant.UDF_JAR_TMP_PATH;
import static com.dlink.constant.PathConstant.UDF_VERSION_RULE;
import com.dlink.constant.PathConstant; import com.dlink.constant.PathConstant;
import com.dlink.pool.ClassEntity; import com.dlink.pool.ClassEntity;
import com.dlink.pool.ClassPool; import com.dlink.pool.ClassPool;
import com.dlink.process.context.ProcessContextHolder;
import com.dlink.process.model.ProcessEntity;
import org.apache.commons.lang3.StringUtils;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
...@@ -34,6 +34,8 @@ import java.util.Collections; ...@@ -34,6 +34,8 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.control.CompilerConfiguration;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -55,11 +57,27 @@ import groovy.lang.GroovyClassLoader; ...@@ -55,11 +57,27 @@ import groovy.lang.GroovyClassLoader;
* @since 2021/12/27 23:25 * @since 2021/12/27 23:25
*/ */
public class UDFUtil { public class UDFUtil {
protected static final Logger log = LoggerFactory.getLogger(UDFUtil.class); protected static final Logger log = LoggerFactory.getLogger(UDFUtil.class);
/** /**
* 存放 udf md5与版本对应的k,v值 * 存放 udf md5与版本对应的k,v值
*/ */
protected static final Map<String, Integer> UDF_MD5_MAP = new HashMap<>(); protected static final Map<String, Integer> UDF_MD5_MAP = new HashMap<>();
private static final String FUNCTION_REGEX = "function (.*?)'(.*?)'";
public static List<String> getUDFClassName(String statement) {
ProcessEntity process = ProcessContextHolder.getProcess();
process.info("Parse UDF class name:");
Pattern pattern = Pattern.compile(FUNCTION_REGEX, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(statement);
List<String> classNameList = new ArrayList<>();
while (matcher.find()) {
classNameList.add(matcher.group(2));
}
process.info(StringUtils.join(",", classNameList));
process.info(StrUtil.format("A total of {} UDF have been Parsed.", classNameList.size()));
return classNameList;
}
public static Boolean buildClass(String code) { public static Boolean buildClass(String code) {
CustomStringJavaCompiler compiler = new CustomStringJavaCompiler(code); CustomStringJavaCompiler compiler = new CustomStringJavaCompiler(code);
...@@ -93,8 +111,8 @@ public class UDFUtil { ...@@ -93,8 +111,8 @@ public class UDFUtil {
List<String> successList = new ArrayList<>(); List<String> successList = new ArrayList<>();
List<String> failedList = new ArrayList<>(); List<String> failedList = new ArrayList<>();
String tmpPath = PathConstant.UDF_PATH; String tmpPath = PathConstant.UDF_PATH;
String udfJarPath = UDF_JAR_TMP_PATH; String udfJarPath = PathConstant.UDF_JAR_TMP_PATH;
//删除jar缓存 // 删除jar缓存
FileUtil.del(udfJarPath); FileUtil.del(udfJarPath);
codeList.forEach(code -> { codeList.forEach(code -> {
CustomStringJavaCompiler compiler = new CustomStringJavaCompiler(code); CustomStringJavaCompiler compiler = new CustomStringJavaCompiler(code);
...@@ -110,14 +128,18 @@ public class UDFUtil { ...@@ -110,14 +128,18 @@ public class UDFUtil {
failedList.add(className); failedList.add(className);
} }
}); });
String[] clazzs = successList.stream().map(className -> StrUtil.replace(className, ".", "/") + ".class").toArray(String[]::new); String[] clazzs = successList.stream().map(className -> StrUtil.replace(className, ".", "/") + ".class")
InputStream[] fileInputStreams = successList.stream().map(className -> tmpPath + StrUtil.replace(className, ".", "/") + ".class").map(FileUtil::getInputStream).toArray(InputStream[]::new); .toArray(String[]::new);
InputStream[] fileInputStreams =
successList.stream().map(className -> tmpPath + StrUtil.replace(className, ".", "/") + ".class")
.map(FileUtil::getInputStream).toArray(InputStream[]::new);
// 编译好的文件打包jar // 编译好的文件打包jar
try (ZipUtils zipWriter = new ZipUtils(FileUtil.file(udfJarPath), Charset.defaultCharset())) { try (ZipUtils zipWriter = new ZipUtils(FileUtil.file(udfJarPath), Charset.defaultCharset())) {
zipWriter.add(clazzs, fileInputStreams); zipWriter.add(clazzs, fileInputStreams);
} }
String md5 = md5sum(udfJarPath); String md5 = md5sum(udfJarPath);
return MapUtil.builder("success", successList).put("failed", failedList).put("md5", Collections.singletonList(md5)).build(); return MapUtil.builder("success", successList).put("failed", failedList)
.put("md5", Collections.singletonList(md5)).build();
} }
/** /**
...@@ -138,16 +160,16 @@ public class UDFUtil { ...@@ -138,16 +160,16 @@ public class UDFUtil {
if (UDF_MD5_MAP.isEmpty()) { if (UDF_MD5_MAP.isEmpty()) {
scanUDFMD5(); scanUDFMD5();
} }
//2. 如果有匹配的,返回对应udf 版本,没有则构建jar,对应信息写入 jar // 2. 如果有匹配的,返回对应udf 版本,没有则构建jar,对应信息写入 jar
if (UDF_MD5_MAP.containsKey(md5)) { if (UDF_MD5_MAP.containsKey(md5)) {
FileUtil.del(UDF_JAR_TMP_PATH); FileUtil.del(PathConstant.UDF_JAR_TMP_PATH);
return StrUtil.format("udf-{}.jar", UDF_MD5_MAP.get(md5)); return StrUtil.format("udf-{}.jar", UDF_MD5_MAP.get(md5));
} }
// 3. 生成新版本jar // 3. 生成新版本jar
Integer newVersion = UDF_MD5_MAP.values().size() > 0 ? CollUtil.max(UDF_MD5_MAP.values()) + 1 : 1; Integer newVersion = UDF_MD5_MAP.values().size() > 0 ? CollUtil.max(UDF_MD5_MAP.values()) + 1 : 1;
String jarName = StrUtil.format("udf-{}.jar", newVersion); String jarName = StrUtil.format("udf-{}.jar", newVersion);
String newName = PathConstant.UDF_PATH + jarName; String newName = PathConstant.UDF_PATH + jarName;
FileUtil.rename(FileUtil.file(UDF_JAR_TMP_PATH), newName, true); FileUtil.rename(FileUtil.file(PathConstant.UDF_JAR_TMP_PATH), newName, true);
UDF_MD5_MAP.put(md5, newVersion); UDF_MD5_MAP.put(md5, newVersion);
return jarName; return jarName;
} catch (Exception e) { } catch (Exception e) {
...@@ -161,10 +183,11 @@ public class UDFUtil { ...@@ -161,10 +183,11 @@ public class UDFUtil {
*/ */
private static void scanUDFMD5() { private static void scanUDFMD5() {
List<String> fileList = FileUtil.listFileNames(PathConstant.UDF_PATH); List<String> fileList = FileUtil.listFileNames(PathConstant.UDF_PATH);
fileList.stream().filter(fileName -> ReUtil.isMatch(UDF_JAR_RULE, fileName)).distinct().forEach(fileName -> { fileList.stream().filter(fileName -> ReUtil.isMatch(PathConstant.UDF_JAR_RULE, fileName)).distinct()
Integer version = Convert.toInt(ReUtil.getGroup0(UDF_VERSION_RULE, fileName)); .forEach(fileName -> {
UDF_MD5_MAP.put(md5sum(PathConstant.UDF_PATH + fileName), version); Integer version = Convert.toInt(ReUtil.getGroup0(PathConstant.UDF_VERSION_RULE, fileName));
}); UDF_MD5_MAP.put(md5sum(PathConstant.UDF_PATH + fileName), version);
});
} }
private static String md5sum(String filePath) { private static String md5sum(String filePath) {
......
...@@ -55,7 +55,7 @@ start() { ...@@ -55,7 +55,7 @@ start() {
pid=$(cat ${PIDPATH}/${PIDFILE}) pid=$(cat ${PIDPATH}/${PIDFILE})
if [ -z $pid ]; then if [ -z $pid ]; then
nohup java -Ddruid.mysql.usePingMethod=false -Xms512M -Xmx2048M -XX:PermSize=512M -XX:MaxPermSize=1024M -XX:+HeapDumpOnOutOfMemoryError -Xverify:none -cp ${CLASS_PATH} com.dlink.Dlink >dlink.log 2>&1 & nohup java -Ddruid.mysql.usePingMethod=false -Xms512M -Xmx2048M -XX:PermSize=512M -XX:MaxPermSize=1024M -XX:+HeapDumpOnOutOfMemoryError -Xverify:none -cp ${CLASS_PATH} com.dlink.Dlink >/dev/null 2>&1 &
echo $! >${PIDPATH}/${PIDFILE} echo $! >${PIDPATH}/${PIDFILE}
echo "........................................Start Dlink Successfully........................................" echo "........................................Start Dlink Successfully........................................"
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Licensed to the Apache Software Foundation (ASF) under one or more
~ contributor license agreements. See the NOTICE file distributed with
~ this work for additional information regarding copyright ownership.
~ The ASF licenses this file to You 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.dlink</groupId>
<artifactId>dlink</artifactId>
<version>0.6.8-SNAPSHOT</version>
</parent>
<artifactId>dlink-process</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.dlink</groupId>
<artifactId>dlink-common</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
</dependencies>
</project>
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
package com.dlink.process.context;
import com.dlink.assertion.Asserts;
import com.dlink.process.model.ProcessEntity;
import com.dlink.process.pool.ProcessPool;
/**
* ProcessContextHolder
*
* @author wenmo
* @since 2022/10/16 16:57
*/
public class ProcessContextHolder {
private static final ThreadLocal<ProcessEntity> PROCESS_CONTEXT = new ThreadLocal<>();
public static void setProcess(ProcessEntity process) {
PROCESS_CONTEXT.set(process);
}
public static ProcessEntity getProcess() {
if (Asserts.isNull(PROCESS_CONTEXT.get())) {
return ProcessEntity.NULL_PROCESS;
}
return PROCESS_CONTEXT.get();
}
public static void clear() {
PROCESS_CONTEXT.remove();
}
public static ProcessEntity registerProcess(ProcessEntity process) {
Asserts.checkNull(process, "Process can not be null.");
setProcess(process);
ProcessPool.getInstance().push(process.getName(), process);
return process;
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
package com.dlink.process.model;
import com.dlink.assertion.Asserts;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import cn.hutool.core.util.StrUtil;
/**
* Process
*
* @author wenmo
* @since 2022/10/16 16:30
*/
public class ProcessEntity {
private String pid;
private String name;
private Integer taskId;
private ProcessType type;
private ProcessStatus status;
private LocalDateTime startTime;
private LocalDateTime endTime;
private long time;
private int stepIndex = 0;
private List<ProcessStep> steps;
private Integer userId;
private String userName;
public static final ProcessEntity NULL_PROCESS = new ProcessEntity();
public ProcessEntity() {
}
public ProcessEntity(String pid, String name, Integer taskId, ProcessType type, Integer userId, String userName) {
this.pid = pid;
this.name = name;
this.taskId = taskId;
this.type = type;
this.userId = userId;
this.userName = userName;
}
public ProcessEntity(String name, Integer taskId, ProcessType type, ProcessStatus status, LocalDateTime startTime,
LocalDateTime endTime, long time,
List<ProcessStep> steps, Integer userId, String userName) {
this.name = name;
this.taskId = taskId;
this.type = type;
this.status = status;
this.startTime = startTime;
this.endTime = endTime;
this.time = time;
this.steps = steps;
this.userId = userId;
this.userName = userName;
}
public static ProcessEntity init(ProcessType type, Integer userId, String userName) {
return init(type.getValue() + "_TEMP", null, type, userId, userName);
}
public static ProcessEntity init(Integer taskId, ProcessType type, Integer userId, String userName) {
return init(type.getValue() + taskId, taskId, type, userId, userName);
}
public static ProcessEntity init(String name, Integer taskId, ProcessType type, Integer userId, String userName) {
ProcessEntity process = new ProcessEntity(UUID.randomUUID().toString(), name, taskId, type, userId, userName);
process.setStatus(ProcessStatus.INITIALIZING);
process.setStartTime(LocalDateTime.now());
process.setSteps(new ArrayList<>());
process.getSteps().add(ProcessStep.init());
process.nextStep();
return process;
}
public void start() {
if (isNullProcess()) {
return;
}
steps.get(stepIndex - 1).setEndTime(LocalDateTime.now());
setStatus(ProcessStatus.RUNNING);
steps.add(ProcessStep.run());
nextStep();
}
public void finish() {
if (isNullProcess()) {
return;
}
steps.get(stepIndex - 1).setEndTime(LocalDateTime.now());
setStatus(ProcessStatus.FINISHED);
setEndTime(LocalDateTime.now());
setTime(getEndTime().compareTo(getStartTime()));
}
public void config(String str) {
if (isNullProcess()) {
return;
}
steps.get(stepIndex - 1).appendInfo(
StrUtil.format("\n[{}] {} CONFIG: {}", type.getValue(), LocalDateTime.now(), str));
}
public void info(String str) {
if (isNullProcess()) {
return;
}
steps.get(stepIndex - 1).appendInfo(
StrUtil.format("\n[{}] {} INFO: {}", type.getValue(), LocalDateTime.now(), str));
}
public void infoSuccess() {
if (isNullProcess()) {
return;
}
steps.get(stepIndex - 1).appendInfo("Success.");
}
public void infoFail() {
if (isNullProcess()) {
return;
}
steps.get(stepIndex - 1).appendInfo("Fail.");
}
public void error(String str) {
if (isNullProcess()) {
return;
}
steps.get(stepIndex - 1).appendInfo(
StrUtil.format("\n[{}] {} ERROR: {}", type.getValue(), LocalDateTime.now(), str));
steps.get(stepIndex - 1).appendError(
StrUtil.format("\n[{}] {} ERROR: {}", type.getValue(), LocalDateTime.now(), str));
}
public void nextStep() {
if (isNullProcess()) {
return;
}
stepIndex++;
}
public boolean isNullProcess() {
return Asserts.isNullString(pid);
}
public boolean isActiveProcess() {
return status.isActiveStatus();
}
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getTaskId() {
return taskId;
}
public void setTaskId(Integer taskId) {
this.taskId = taskId;
}
public ProcessType getType() {
return type;
}
public void setType(ProcessType type) {
this.type = type;
}
public ProcessStatus getStatus() {
return status;
}
public void setStatus(ProcessStatus status) {
this.status = status;
}
public LocalDateTime getStartTime() {
return startTime;
}
public void setStartTime(LocalDateTime startTime) {
this.startTime = startTime;
}
public LocalDateTime getEndTime() {
return endTime;
}
public void setEndTime(LocalDateTime endTime) {
this.endTime = endTime;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public List<ProcessStep> getSteps() {
return steps;
}
public void setSteps(List<ProcessStep> steps) {
this.steps = steps;
}
public int getStepIndex() {
return stepIndex;
}
public void setStepIndex(int stepIndex) {
this.stepIndex = stepIndex;
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
package com.dlink.process.model;
import com.dlink.assertion.Asserts;
/**
* ProcessStatus
*
* @author wenmo
* @since 2022/10/16 16:33
*/
public enum ProcessStatus {
INITIALIZING("INITIALIZING"),
RUNNING("RUNNING"),
FAILED("FAILED"),
CANCELED("CANCELED"),
FINISHED("FINISHED"),
UNKNOWN("UNKNOWN");
private String value;
ProcessStatus(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static ProcessStatus get(String value) {
for (ProcessStatus type : ProcessStatus.values()) {
if (Asserts.isEquals(type.getValue(), value)) {
return type;
}
}
return ProcessStatus.UNKNOWN;
}
public boolean equalsValue(String type) {
if (Asserts.isEquals(value, type)) {
return true;
}
return false;
}
public boolean isActiveStatus() {
switch (this) {
case INITIALIZING:
case RUNNING:
return true;
default:
return false;
}
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
package com.dlink.process.model;
import java.time.LocalDateTime;
/**
* ProcessStep
*
* @author wenmo
* @since 2022/10/16 16:46
*/
public class ProcessStep {
private ProcessStatus stepStatus;
private LocalDateTime startTime;
private LocalDateTime endTime;
private long time;
private StringBuilder info = new StringBuilder();
private StringBuilder error = new StringBuilder();
private boolean isError = false;
public ProcessStep() {
}
public ProcessStep(ProcessStatus stepStatus, LocalDateTime startTime) {
this.stepStatus = stepStatus;
this.startTime = startTime;
}
public ProcessStep(int index, ProcessStatus stepStatus, LocalDateTime startTime, LocalDateTime endTime, long time,
StringBuilder info, StringBuilder error) {
this.stepStatus = stepStatus;
this.startTime = startTime;
this.endTime = endTime;
this.time = time;
this.info = info;
this.error = error;
}
public static ProcessStep init() {
return new ProcessStep(ProcessStatus.INITIALIZING, LocalDateTime.now());
}
public static ProcessStep run() {
return new ProcessStep(ProcessStatus.RUNNING, LocalDateTime.now());
}
public void appendInfo(String str) {
info.append(str);
}
public void appendError(String str) {
error.append(str);
isError = true;
}
public ProcessStatus getStepStatus() {
return stepStatus;
}
public void setStepStatus(ProcessStatus stepStatus) {
this.stepStatus = stepStatus;
}
public LocalDateTime getStartTime() {
return startTime;
}
public void setStartTime(LocalDateTime startTime) {
this.startTime = startTime;
}
public LocalDateTime getEndTime() {
return endTime;
}
public void setEndTime(LocalDateTime endTime) {
this.endTime = endTime;
this.time = endTime.compareTo(startTime);
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public StringBuilder getInfo() {
return info;
}
public void setInfo(StringBuilder info) {
this.info = info;
}
public StringBuilder getError() {
return error;
}
public void setError(StringBuilder error) {
this.error = error;
}
public boolean isError() {
return isError;
}
public void setError(boolean error) {
isError = error;
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
package com.dlink.process.model;
import com.dlink.assertion.Asserts;
/**
* ProcessType
*
* @author wenmo
* @since 2022/10/16 16:33
*/
public enum ProcessType {
FLINKEXPLAIN("FlinkExplain"),
FLINKSUBMIT("FlinkSubmit"),
SQLEXPLAIN("SQLExplain"),
SQKSUBMIT("SQLSubmit"),
UNKNOWN("Unknown");
private String value;
ProcessType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static ProcessType get(String value) {
for (ProcessType type : ProcessType.values()) {
if (Asserts.isEquals(type.getValue(), value)) {
return type;
}
}
return ProcessType.UNKNOWN;
}
public boolean equalsValue(String type) {
if (Asserts.isEquals(value, type)) {
return true;
}
return false;
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
package com.dlink.process.pool;
import com.dlink.pool.AbstractPool;
import com.dlink.process.model.ProcessEntity;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* ProcessPool
*
* @author wenmo
* @since 2022/10/16 17:00
*/
public class ProcessPool extends AbstractPool<ProcessEntity> {
private static volatile Map<String, ProcessEntity> processEntityMap = new ConcurrentHashMap<>();
private static ProcessPool instance = new ProcessPool();
public static ProcessPool getInstance() {
return instance;
}
@Override
public Map<String, ProcessEntity> getMap() {
return processEntityMap;
}
@Override
public void refresh(ProcessEntity entity) {
}
}
...@@ -182,6 +182,12 @@ export default [ ...@@ -182,6 +182,12 @@ export default [
icon: 'desktop', icon: 'desktop',
component: './SettingCenter/SystemInfo', component: './SettingCenter/SystemInfo',
}, },
{
path: '/settingcenter/processList',
name: 'processList',
icon: 'desktop',
component: './SettingCenter/ProcessList',
},
], ],
}, },
{ {
......
...@@ -102,6 +102,7 @@ export default { ...@@ -102,6 +102,7 @@ export default {
'menu.settings': 'Setting Center', 'menu.settings': 'Setting Center',
'menu.settings.flinkConfig': 'Flink Settings', 'menu.settings.flinkConfig': 'Flink Settings',
'menu.settings.systemInfo': 'System Info', 'menu.settings.systemInfo': 'System Info',
'menu.settings.processList': 'Process List',
'menu.about': 'About', 'menu.about': 'About',
}; };
...@@ -107,6 +107,7 @@ export default { ...@@ -107,6 +107,7 @@ export default {
'menu.settings': '配置中心', 'menu.settings': '配置中心',
'menu.settings.flinkConfig': 'Flink 配置', 'menu.settings.flinkConfig': 'Flink 配置',
'menu.settings.systemInfo': '系统信息', 'menu.settings.systemInfo': '系统信息',
'menu.settings.processList': '进程列表',
'menu.about': '关于', 'menu.about': '关于',
}; };
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
export type ProcessItem = {
pid: string,
name: string,
taskId: number,
type: string,
status: string,
startTime: Date,
endTime: Date,
time: number,
steps: ProcessStep[],
userId: number,
userName: string,
};
export type ProcessStep = {
stepStatus: string,
startTime: Date,
endTime: Date,
time: number,
info: string,
error: string,
isError: boolean,
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
import React, {useRef, useState} from "react";
import ProTable, {ActionType, ProColumns} from "@ant-design/pro-table";
import {Drawer} from 'antd';
import {PageContainer} from '@ant-design/pro-layout';
import ProDescriptions from '@ant-design/pro-descriptions';
import {getData} from "@/components/Common/crud";
import {ProcessItem} from "@/pages/SettingCenter/ProcessList/data";
const url = '/api/process/listAllProcess';
const ProcessList: React.FC<{}> = (props: any) => {
const {dispatch} = props;
const [row, setRow] = useState<ProcessItem>();
const actionRef = useRef<ActionType>();
const columns: ProColumns<ProcessItem>[] = [
{
title: '进程ID',
dataIndex: 'pid',
sorter: true,
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
},
{
title: '进程名',
sorter: true,
dataIndex: 'name',
},
{
title: '任务ID',
sorter: true,
dataIndex: 'taskId',
},
{
title: '类型',
sorter: true,
dataIndex: 'type',
filters: [
{
text: 'FlinkExplain',
value: 'FlinkExplain',
},{
text: 'FlinkSubmit',
value: 'FlinkSubmit',
},{
text: 'SQLExplain',
value: 'SQLExplain',
},{
text: 'SQLSubmit',
value: 'SQLSubmit',
},{
text: 'Unknown',
value: 'Unknown',
},
],
filterMultiple: false,
valueEnum: {
'FlinkExplain': {text: 'FlinkExplain'},
'FlinkSubmit': {text: 'FlinkSubmit'},
'SQLExplain': {text: 'SQLExplain'},
'SQLSubmit': {text: 'SQLSubmit'},
'Unknown': {text: 'Unknown'},
},
},{
title: '状态',
sorter: true,
dataIndex: 'status',
filters: [
{
text: 'INITIALIZING',
value: 'INITIALIZING',
},{
text: 'RUNNING',
value: 'RUNNING',
},{
text: 'FAILED',
value: 'FAILED',
},{
text: 'CANCELED',
value: 'CANCELED',
},{
text: 'FINISHED',
value: 'FINISHED',
},{
text: 'UNKNOWN',
value: 'UNKNOWN',
},
],
filterMultiple: false,
valueEnum: {
'INITIALIZING': {text: 'INITIALIZING'},
'RUNNING': {text: 'RUNNING'},
'FAILED': {text: 'FAILED'},
'CANCELED': {text: 'CANCELED'},
'FINISHED': {text: 'FINISHED'},
'UNKNOWN': {text: 'UNKNOWN'},
},
},
{
title: '开始时间',
dataIndex: 'startTime',
sorter: true,
valueType: 'dateTime',
},
{
title: '结束时间',
dataIndex: 'endTime',
sorter: true,
valueType: 'dateTime',
}, {
title: '耗时',
sorter: true,
dataIndex: 'time',
}, {
title: '操作人ID',
sorter: true,
dataIndex: 'userId',
}, {
title: '操作人名',
sorter: true,
dataIndex: 'userName',
}
];
return (
<PageContainer title={false}>
<ProTable
actionRef={actionRef}
rowKey="pid"
request={(params, sorter, filter) => getData(url, {active:false})}
columns={columns}
search={false}
/>
<Drawer
width={600}
visible={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.pid && (
<ProDescriptions<ProcessItem>
column={2}
title={row?.pid}
request={async () => ({
data: row || {},
})}
params={{
pid: row?.pid,
}}
columns={columns}
/>
)}
</Drawer>
</PageContainer>
);
};
export default ProcessList;
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
<module>dlink-web</module> <module>dlink-web</module>
<module>dlink-admin</module> <module>dlink-admin</module>
<module>dlink-assembly</module> <module>dlink-assembly</module>
<module>dlink-process</module>
</modules> </modules>
<properties> <properties>
...@@ -452,6 +453,11 @@ ...@@ -452,6 +453,11 @@
<artifactId>dlink-scheduler</artifactId> <artifactId>dlink-scheduler</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.dlink</groupId>
<artifactId>dlink-process</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment