From 701495116f067404cd827d4fa734e9b0996de1d5 Mon Sep 17 00:00:00 2001
From: samz406
Date: Thu, 19 Sep 2019 11:31:19 +0800
Subject: [PATCH 01/42] misspell words (#817)
---
docs/en_US/EasyScheduler Proposal.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/en_US/EasyScheduler Proposal.md b/docs/en_US/EasyScheduler Proposal.md
index 965605f63b..552067fe47 100644
--- a/docs/en_US/EasyScheduler Proposal.md
+++ b/docs/en_US/EasyScheduler Proposal.md
@@ -6,7 +6,7 @@ EasyScheduler is a distributed ETL scheduling engine with powerful DAG visualiza
## Proposal
-EasyScheduler provides many easy-to-use features to accelerate the engineer enficiency on data ETL workflow job. We propose a new concept of 'instance of process' and 'instance of task' to let developers to tuning their jobs on the running state of workflow instead of changing the task's template. Its main objectives are as follows:
+EasyScheduler provides many easy-to-use features to accelerate the engineer efficiency on data ETL workflow job. We propose a new concept of 'instance of process' and 'instance of task' to let developers to tuning their jobs on the running state of workflow instead of changing the task's template. Its main objectives are as follows:
- Define the complex tasks' dependencies & triggers in a DAG graph by dragging and dropping.
- Support cluster HA.
From 0392dad785784cc87a3f75b393d72dca96285673 Mon Sep 17 00:00:00 2001
From: 0xflotus <0xflotus@gmail.com>
Date: Thu, 19 Sep 2019 05:36:11 +0200
Subject: [PATCH 02/42] (Docs): Fixed some typo errors (#811)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Update EasyScheduler Proposal.md
* Update frontend-deployment.md
* Update frontend-development.md
* Update 前端开发文档.md
* Update system-manual.md
* Update HttpClientTest.java
* Update 系统使用手册.md
---
docs/en_US/EasyScheduler Proposal.md | 6 +++---
docs/en_US/frontend-deployment.md | 2 +-
docs/en_US/frontend-development.md | 4 ++--
docs/en_US/system-manual.md | 6 +++---
docs/zh_CN/前端开发文档.md | 4 ++--
docs/zh_CN/系统使用手册.md | 2 +-
.../src/test/java/cn/escheduler/api/HttpClientTest.java | 6 +++---
7 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/docs/en_US/EasyScheduler Proposal.md b/docs/en_US/EasyScheduler Proposal.md
index 552067fe47..6bcea73540 100644
--- a/docs/en_US/EasyScheduler Proposal.md
+++ b/docs/en_US/EasyScheduler Proposal.md
@@ -30,7 +30,7 @@ The codes are already under Apache License Version 2.0.
We want to find a data processing tool with the following features:
-- Easy to use,developers can build a ETL process with a very simple drag and drop operation. not only for ETL developers,people who can't write code also can use this tool for ETL operation such as system adminitrator.
+- Easy to use,developers can build a ETL process with a very simple drag and drop operation. not only for ETL developers,people who can't write code also can use this tool for ETL operation such as system administrator.
- Solving the problem of "complex task dependencies" , and it can monitor the ETL running status.
- Support multi-tenant.
- Support many task types: Shell, MR, Spark, SQL (mysql, postgresql, hive, sparksql), Python, Sub_Process, Procedure, etc.
@@ -73,7 +73,7 @@ Thus, it is very unlikely that EasyScheduler becomes orphaned.
EasyScheduler's core developers have been running it as a community-oriented open source project for some time, several of them already have experience working with open source communities, they are also active in presto, alluxio and other projects. At the same time, we will learn more open source experiences by following the Apache way in our incubator journey.
-### Homogenous Developers
+### Homogeneous Developers
The current developers work across a variety of organizations including Analysys, guandata and hydee;
some individual developers are accepted as developers of EasyScheduler as well.
@@ -110,7 +110,7 @@ The project consists of three distinct codebases: core and document. The address
## Source and Intellectual Property Submission Plan
-As soon as EasyScheduler is approved to join Apache Incubator, Analysys will provide the Software Grant Agreement(SGA) and intial committers will submit ICLA(s). The code is already licensed under the Apache Software License, version 2.0.
+As soon as EasyScheduler is approved to join Apache Incubator, Analysys will provide the Software Grant Agreement(SGA) and initial committers will submit ICLA(s). The code is already licensed under the Apache Software License, version 2.0.
## External Dependencies
diff --git a/docs/en_US/frontend-deployment.md b/docs/en_US/frontend-deployment.md
index 46372c2d88..919caf1485 100644
--- a/docs/en_US/frontend-deployment.md
+++ b/docs/en_US/frontend-deployment.md
@@ -64,7 +64,7 @@ server {
index index.html index.html;
}
location /escheduler {
- proxy_pass http://192.168.xx.xx:12345; # nterface address (self-modifying)
+ proxy_pass http://192.168.xx.xx:12345; # interface address (self-modifying)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header x_real_ipP $remote_addr;
diff --git a/docs/en_US/frontend-development.md b/docs/en_US/frontend-development.md
index fc27f40613..286c598dbc 100644
--- a/docs/en_US/frontend-development.md
+++ b/docs/en_US/frontend-development.md
@@ -63,7 +63,7 @@ Copy it to the corresponding directory of the server (front-end service static p
Visit address` http://localhost:8888/#/`
-#### Start with node and daemon under Liunx
+#### Start with node and daemon under Linux
Install pm2 `npm install -g pm2`
@@ -238,7 +238,7 @@ The internal common component of the `src/js/module/components` project writes t
├── conditions
├── conditions.vue
└── _source
- └── serach.vue
+ └── search.vue
└── util.js
```
diff --git a/docs/en_US/system-manual.md b/docs/en_US/system-manual.md
index d5a63af80d..d571e1d66f 100644
--- a/docs/en_US/system-manual.md
+++ b/docs/en_US/system-manual.md
@@ -340,7 +340,7 @@ conf/common/hadoop.properties
- Queues are used to execute spark, mapreduce and other programs, which require the use of "queue" parameters.
-- "Security" - > "Queue Manage" - > "Creat Queue"
+- "Security" - > "Queue Manage" - > "Create Queue"
@@ -403,7 +403,7 @@ conf/common/hadoop.properties
try {
// execute
response = httpclient.execute(httpPost);
- // eponse status code 200
+ // response status code 200
if (response.getStatusLine().getStatusCode() == 200) {
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
@@ -533,7 +533,7 @@ conf/common/hadoop.properties
-- Datasource: The data source type of stored procedure supports MySQL and POSTGRRESQL, and chooses the corresponding data source.
+- Datasource: The data source type of stored procedure supports MySQL and POSTGRESQL, and chooses the corresponding data source.
- Method: The method name of the stored procedure
- Custom parameters: Custom parameter types of stored procedures support IN and OUT, and data types support nine data types: VARCHAR, INTEGER, LONG, FLOAT, DOUBLE, DATE, TIME, TIMESTAMP and BOOLEAN.
diff --git a/docs/zh_CN/前端开发文档.md b/docs/zh_CN/前端开发文档.md
index b3e8aa82d9..f805f5ed8c 100644
--- a/docs/zh_CN/前端开发文档.md
+++ b/docs/zh_CN/前端开发文档.md
@@ -64,7 +64,7 @@ npm install node-sass --unsafe-perm //单独安装node-sass依赖
访问地址 `http://localhost:8888/#/`
-#### Liunx下使用node启动并且守护进程
+#### Linux下使用node启动并且守护进程
安装pm2 `npm install -g pm2`
@@ -237,7 +237,7 @@ export default {
├── conditions
├── conditions.vue
└── _source
- └── serach.vue
+ └── search.vue
└── util.js
```
diff --git a/docs/zh_CN/系统使用手册.md b/docs/zh_CN/系统使用手册.md
index 4d0cc21195..348cc2b36a 100644
--- a/docs/zh_CN/系统使用手册.md
+++ b/docs/zh_CN/系统使用手册.md
@@ -391,7 +391,7 @@ conf/common/hadoop.properties
try {
// execute
response = httpclient.execute(httpPost);
- // eponse status code 200
+ // response status code 200
if (response.getStatusLine().getStatusCode() == 200) {
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
diff --git a/escheduler-api/src/test/java/cn/escheduler/api/HttpClientTest.java b/escheduler-api/src/test/java/cn/escheduler/api/HttpClientTest.java
index b2495a2f9d..1d527b563c 100644
--- a/escheduler-api/src/test/java/cn/escheduler/api/HttpClientTest.java
+++ b/escheduler-api/src/test/java/cn/escheduler/api/HttpClientTest.java
@@ -59,7 +59,7 @@ public class HttpClientTest {
try {
// execute
response = httpclient.execute(httpPost);
- // eponse status code 200
+ // response status code 200
if (response.getStatusLine().getStatusCode() == 200) {
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
logger.info(content);
@@ -96,7 +96,7 @@ public class HttpClientTest {
try {
// execute http get request
response = httpclient.execute(httpGet);
- // reponse status code 200
+ // response status code 200
if (response.getStatusLine().getStatusCode() == 200) {
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
logger.info("start--------------->");
@@ -139,7 +139,7 @@ public class HttpClientTest {
try {
// execute http get request
response = httpclient.execute(httpGet);
- // reponse status code 200
+ // response status code 200
if (response.getStatusLine().getStatusCode() == 200) {
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
logger.info("start--------------->");
From df48c99577f31373ead5bf76ae12db457dcbb000 Mon Sep 17 00:00:00 2001
From: Pickle <850885154@qq.com>
Date: Thu, 19 Sep 2019 11:45:55 +0800
Subject: [PATCH 03/42] fix singleton with volatile (#818)
---
.../src/main/java/cn/escheduler/alert/AlertServer.java | 2 +-
.../java/cn/escheduler/common/thread/ThreadPoolExecutors.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/escheduler-alert/src/main/java/cn/escheduler/alert/AlertServer.java b/escheduler-alert/src/main/java/cn/escheduler/alert/AlertServer.java
index 8de3a65d6c..27c5f0ce56 100644
--- a/escheduler-alert/src/main/java/cn/escheduler/alert/AlertServer.java
+++ b/escheduler-alert/src/main/java/cn/escheduler/alert/AlertServer.java
@@ -39,7 +39,7 @@ public class AlertServer {
private AlertSender alertSender;
- private static AlertServer instance;
+ private static volatile AlertServer instance;
private AlertServer() {
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/thread/ThreadPoolExecutors.java b/escheduler-common/src/main/java/cn/escheduler/common/thread/ThreadPoolExecutors.java
index 8329e8c18a..ea03026d3a 100644
--- a/escheduler-common/src/main/java/cn/escheduler/common/thread/ThreadPoolExecutors.java
+++ b/escheduler-common/src/main/java/cn/escheduler/common/thread/ThreadPoolExecutors.java
@@ -40,7 +40,7 @@ public class ThreadPoolExecutors {
private static final Logger logger = LoggerFactory.getLogger(ThreadPoolExecutors.class);
private static Executor executor;
- private static ThreadPoolExecutors threadPoolExecutors;
+ private static volatile ThreadPoolExecutors threadPoolExecutors;
private ThreadPoolExecutors(){}
From 42dce508fbabfd339aa47ae3aef4fae491aabd9e Mon Sep 17 00:00:00 2001
From: Pickle <850885154@qq.com>
Date: Thu, 19 Sep 2019 11:50:23 +0800
Subject: [PATCH 04/42] Replace StringBuffer with StringBuilder inside the
method (#816)
---
.../java/cn/escheduler/common/shell/AbstractShell.java | 2 +-
.../dao/mapper/ProcessInstanceMapperProvider.java | 8 ++++----
.../cn/escheduler/dao/mapper/ScheduleMapperProvider.java | 2 +-
.../escheduler/dao/mapper/TaskInstanceMapperProvider.java | 8 ++++----
4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/shell/AbstractShell.java b/escheduler-common/src/main/java/cn/escheduler/common/shell/AbstractShell.java
index 1250732632..0880c4d5bb 100644
--- a/escheduler-common/src/main/java/cn/escheduler/common/shell/AbstractShell.java
+++ b/escheduler-common/src/main/java/cn/escheduler/common/shell/AbstractShell.java
@@ -157,7 +157,7 @@ public abstract class AbstractShell {
BufferedReader inReader =
new BufferedReader(new InputStreamReader(process
.getInputStream()));
- final StringBuffer errMsg = new StringBuffer();
+ final StringBuilder errMsg = new StringBuilder();
// read error and input streams as this would free up the buffers
// free the error stream buffer
diff --git a/escheduler-dao/src/main/java/cn/escheduler/dao/mapper/ProcessInstanceMapperProvider.java b/escheduler-dao/src/main/java/cn/escheduler/dao/mapper/ProcessInstanceMapperProvider.java
index 78165e3f9a..9bbd3e336e 100644
--- a/escheduler-dao/src/main/java/cn/escheduler/dao/mapper/ProcessInstanceMapperProvider.java
+++ b/escheduler-dao/src/main/java/cn/escheduler/dao/mapper/ProcessInstanceMapperProvider.java
@@ -354,7 +354,7 @@ public class ProcessInstanceMapperProvider {
* @return
*/
public String listByStatus(Map parameter) {
- StringBuffer strStates = new StringBuffer();
+ StringBuilder strStates = new StringBuilder();
int[] stateArray = (int[]) parameter.get("states");
for(int i=0;i parameter) {
- StringBuffer strStates = new StringBuffer();
+ StringBuilder strStates = new StringBuilder();
int[] stateArray = (int[]) parameter.get("states");
for(int i=0;i parameter) {
- StringBuffer strStates = new StringBuffer();
+ StringBuilder strStates = new StringBuilder();
int[] stateArray = (int[]) parameter.get("states");
for(int i=0;i parameter) {
- StringBuffer strStates = new StringBuffer();
+ StringBuilder strStates = new StringBuilder();
int[] stateArray = (int[]) parameter.get("states");
for(int i=0;i parameter) {
- StringBuffer strIds = new StringBuffer();
+ StringBuilder strIds = new StringBuilder();
int[] idsArray = (int[]) parameter.get("processDefineIds");
for(int i=0;i parameter) {
- StringBuffer strStates = new StringBuffer();
+ StringBuilder strStates = new StringBuilder();
int[] stateArray = (int[]) parameter.get("states");
for(int i=0;i parameter) {
- StringBuffer strStates = new StringBuffer();
+ StringBuilder strStates = new StringBuilder();
int[] stateArray = (int[]) parameter.get("states");
for(int i=0;i parameter) {
- StringBuffer strStates = new StringBuffer();
+ StringBuilder strStates = new StringBuilder();
int[] stateArray = (int[]) parameter.get("states");
int state = ExecutionStatus.NEED_FAULT_TOLERANCE.ordinal();
for(int i=0;i parameter){
- StringBuffer taskIdsStr = new StringBuffer();
+ StringBuilder taskIdsStr = new StringBuilder();
int[] stateArray = (int[]) parameter.get("taskIds");
for(int i=0;i
Date: Thu, 19 Sep 2019 12:28:13 +0800
Subject: [PATCH 05/42] =?UTF-8?q?flink=20task=20support(flink=20=E4=BB=BB?=
=?UTF-8?q?=E5=8A=A1=E6=94=AF=E6=8C=81)=20(#711)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* flink任务支持
* flink任务支持
* Update zh_CN.js
* Update FlinkArgsUtils.java
* Update .escheduler_env.sh
---
.../java/cn/escheduler/common/Constants.java | 14 +
.../cn/escheduler/common/enums/TaskType.java | 3 +-
.../common/task/flink/FlinkParameters.java | 219 ++++++++++
.../common/utils/TaskParametersUtils.java | 3 +
.../server/utils/FlinkArgsUtils.java | 110 +++++
.../server/worker/task/AbstractTask.java | 3 +
.../server/worker/task/TaskManager.java | 3 +
.../server/worker/task/flink/FlinkTask.java | 118 ++++++
.../js/conf/home/pages/dag/_source/config.js | 4 +
.../js/conf/home/pages/dag/_source/dag.scss | 3 +
.../pages/dag/_source/formModel/formModel.vue | 128 +++---
.../dag/_source/formModel/tasks/flink.vue | 388 ++++++++++++++++++
.../conf/home/pages/dag/img/toobar_flink.svg | 211 ++++++++++
.../src/js/module/i18n/locale/zh_CN.js | 6 +-
.../docs/zh_CN/_book/images/flink_edit.png | Bin 0 -> 123946 bytes
script/env/.escheduler_env.sh | 4 +-
16 files changed, 1153 insertions(+), 64 deletions(-)
create mode 100644 escheduler-common/src/main/java/cn/escheduler/common/task/flink/FlinkParameters.java
create mode 100644 escheduler-server/src/main/java/cn/escheduler/server/utils/FlinkArgsUtils.java
create mode 100644 escheduler-server/src/main/java/cn/escheduler/server/worker/task/flink/FlinkTask.java
create mode 100644 escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue
create mode 100644 escheduler-ui/src/js/conf/home/pages/dag/img/toobar_flink.svg
create mode 100644 escheduler-ui/src/view/docs/zh_CN/_book/images/flink_edit.png
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/Constants.java b/escheduler-common/src/main/java/cn/escheduler/common/Constants.java
index 10a4460678..7eaa6b7926 100644
--- a/escheduler-common/src/main/java/cn/escheduler/common/Constants.java
+++ b/escheduler-common/src/main/java/cn/escheduler/common/Constants.java
@@ -906,4 +906,18 @@ public final class Constants {
* hive conf
*/
public static final String HIVE_CONF = "hiveconf:";
+
+ //flink 任务
+ public static final String FLINK_YARN_CLUSTER = "yarn-cluster";
+ public static final String FLINK_RUN_MODE = "-m";
+ public static final String FLINK_YARN_SLOT = "-ys";
+ public static final String FLINK_APP_NAME = "-ynm";
+ public static final String FLINK_TASK_MANAGE = "-yn";
+
+ public static final String FLINK_JOB_MANAGE_MEM = "-yjm";
+ public static final String FLINK_TASK_MANAGE_MEM = "-ytm";
+ public static final String FLINK_detach = "-d";
+ public static final String FLINK_MAIN_CLASS = "-c";
+
+
}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskType.java
index 1d589167e3..7e4fde6a34 100644
--- a/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskType.java
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskType.java
@@ -29,8 +29,9 @@ public enum TaskType {
* 5 SPARK
* 6 PYTHON
* 7 DEPENDENT
+ * 8 FLINK
*/
- SHELL,SQL, SUB_PROCESS,PROCEDURE,MR,SPARK,PYTHON,DEPENDENT;
+ SHELL,SQL, SUB_PROCESS,PROCEDURE,MR,SPARK,PYTHON,DEPENDENT,FLINK;
public static boolean typeIsNormalTask(String typeName) {
TaskType taskType = TaskType.valueOf(typeName);
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/flink/FlinkParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/flink/FlinkParameters.java
new file mode 100644
index 0000000000..54dfcb7103
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/flink/FlinkParameters.java
@@ -0,0 +1,219 @@
+/*
+ * 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 cn.escheduler.common.task.flink;
+
+import cn.escheduler.common.enums.ProgramType;
+import cn.escheduler.common.process.ResourceInfo;
+import cn.escheduler.common.task.AbstractParameters;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * spark parameters
+ */
+public class FlinkParameters extends AbstractParameters {
+
+ /**
+ * major jar
+ */
+ private ResourceInfo mainJar;
+
+ /**
+ * major class
+ */
+ private String mainClass;
+
+ /**
+ * deploy mode yarn-cluster yarn-client yarn-local
+ */
+ private String deployMode;
+
+ /**
+ * arguments
+ */
+ private String mainArgs;
+
+ /**
+ * slot个数
+ */
+ private int slot;
+
+ /**
+ *Yarn application的名字
+ */
+
+ private String appName;
+
+ /**
+ * taskManager 数量
+ */
+ private int taskManager;
+
+ /**
+ * jobManagerMemory 内存大小
+ */
+ private String jobManagerMemory ;
+
+ /**
+ * taskManagerMemory内存大小
+ */
+ private String taskManagerMemory;
+
+ /**
+ * resource list
+ */
+ private List resourceList;
+
+ /**
+ * The YARN queue to submit to
+ */
+ private String queue;
+
+ /**
+ * other arguments
+ */
+ private String others;
+
+ /**
+ * program type
+ * 0 JAVA,1 SCALA,2 PYTHON
+ */
+ private ProgramType programType;
+
+ public ResourceInfo getMainJar() {
+ return mainJar;
+ }
+
+ public void setMainJar(ResourceInfo mainJar) {
+ this.mainJar = mainJar;
+ }
+
+ public String getMainClass() {
+ return mainClass;
+ }
+
+ public void setMainClass(String mainClass) {
+ this.mainClass = mainClass;
+ }
+
+ public String getDeployMode() {
+ return deployMode;
+ }
+
+ public void setDeployMode(String deployMode) {
+ this.deployMode = deployMode;
+ }
+
+ public String getMainArgs() {
+ return mainArgs;
+ }
+
+ public void setMainArgs(String mainArgs) {
+ this.mainArgs = mainArgs;
+ }
+
+ public int getSlot() {
+ return slot;
+ }
+
+ public void setSlot(int slot) {
+ this.slot = slot;
+ }
+
+ public String getAppName() {
+ return appName;
+ }
+
+ public void setAppName(String appName) {
+ this.appName = appName;
+ }
+
+ public int getTaskManager() {
+ return taskManager;
+ }
+
+ public void setTaskManager(int taskManager) {
+ this.taskManager = taskManager;
+ }
+
+ public String getJobManagerMemory() {
+ return jobManagerMemory;
+ }
+
+ public void setJobManagerMemory(String jobManagerMemory) {
+ this.jobManagerMemory = jobManagerMemory;
+ }
+
+ public String getTaskManagerMemory() {
+ return taskManagerMemory;
+ }
+
+ public void setTaskManagerMemory(String taskManagerMemory) {
+ this.taskManagerMemory = taskManagerMemory;
+ }
+
+ public String getQueue() {
+ return queue;
+ }
+
+ public void setQueue(String queue) {
+ this.queue = queue;
+ }
+
+ public List getResourceList() {
+ return resourceList;
+ }
+
+ public void setResourceList(List resourceList) {
+ this.resourceList = resourceList;
+ }
+
+ public String getOthers() {
+ return others;
+ }
+
+ public void setOthers(String others) {
+ this.others = others;
+ }
+
+ public ProgramType getProgramType() {
+ return programType;
+ }
+
+ public void setProgramType(ProgramType programType) {
+ this.programType = programType;
+ }
+
+ @Override
+ public boolean checkParameters() {
+ return mainJar != null && programType != null;
+ }
+
+
+ @Override
+ public List getResourceFilesList() {
+ if(resourceList !=null ) {
+ this.resourceList.add(mainJar);
+ return resourceList.stream()
+ .map(p -> p.getRes()).collect(Collectors.toList());
+ }
+ return null;
+ }
+
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/utils/TaskParametersUtils.java b/escheduler-common/src/main/java/cn/escheduler/common/utils/TaskParametersUtils.java
index feff4141da..c8ceeb44a2 100644
--- a/escheduler-common/src/main/java/cn/escheduler/common/utils/TaskParametersUtils.java
+++ b/escheduler-common/src/main/java/cn/escheduler/common/utils/TaskParametersUtils.java
@@ -19,6 +19,7 @@ package cn.escheduler.common.utils;
import cn.escheduler.common.enums.TaskType;
import cn.escheduler.common.task.AbstractParameters;
import cn.escheduler.common.task.dependent.DependentParameters;
+import cn.escheduler.common.task.flink.FlinkParameters;
import cn.escheduler.common.task.mr.MapreduceParameters;
import cn.escheduler.common.task.procedure.ProcedureParameters;
import cn.escheduler.common.task.python.PythonParameters;
@@ -63,6 +64,8 @@ public class TaskParametersUtils {
return JSONUtils.parseObject(parameter, PythonParameters.class);
case DEPENDENT:
return JSONUtils.parseObject(parameter, DependentParameters.class);
+ case FLINK:
+ return JSONUtils.parseObject(parameter, FlinkParameters.class);
default:
return null;
}
diff --git a/escheduler-server/src/main/java/cn/escheduler/server/utils/FlinkArgsUtils.java b/escheduler-server/src/main/java/cn/escheduler/server/utils/FlinkArgsUtils.java
new file mode 100644
index 0000000000..308103073d
--- /dev/null
+++ b/escheduler-server/src/main/java/cn/escheduler/server/utils/FlinkArgsUtils.java
@@ -0,0 +1,110 @@
+/*
+ * 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 cn.escheduler.server.utils;
+
+
+import cn.escheduler.common.Constants;
+import cn.escheduler.common.enums.ProgramType;
+import cn.escheduler.common.task.flink.FlinkParameters;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * spark args utils
+ */
+public class FlinkArgsUtils {
+
+ /**
+ * build args
+ * @param param
+ * @return
+ */
+ public static List buildArgs(FlinkParameters param) {
+ List args = new ArrayList<>();
+
+ args.add(Constants.FLINK_RUN_MODE); //-m
+
+ args.add(Constants.FLINK_YARN_CLUSTER); //yarn-cluster
+
+ if (param.getSlot() != 0) {
+ args.add(Constants.FLINK_YARN_SLOT);
+ args.add(String.format("%d", param.getSlot())); //-ys
+ }
+
+ if (StringUtils.isNotEmpty(param.getAppName())) { //-ynm
+ args.add(Constants.FLINK_APP_NAME);
+ args.add(param.getAppName());
+ }
+
+ if (param.getTaskManager() != 0) { //-yn
+ args.add(Constants.FLINK_TASK_MANAGE);
+ args.add(String.format("%d", param.getTaskManager()));
+ }
+
+ if (StringUtils.isNotEmpty(param.getJobManagerMemory())) {
+ args.add(Constants.FLINK_JOB_MANAGE_MEM);
+ args.add(param.getJobManagerMemory()); //-yjm
+ }
+
+ if (StringUtils.isNotEmpty(param.getTaskManagerMemory())) { // -ytm
+ args.add(Constants.FLINK_TASK_MANAGE_MEM);
+ args.add(param.getTaskManagerMemory());
+ }
+ args.add(Constants.FLINK_detach); //-d
+
+
+ if(param.getProgramType() !=null ){
+ if(param.getProgramType()!=ProgramType.PYTHON){
+ if (StringUtils.isNotEmpty(param.getMainClass())) {
+ args.add(Constants.FLINK_MAIN_CLASS); //-c
+ args.add(param.getMainClass()); //main class
+ }
+ }
+ }
+
+ if (param.getMainJar() != null) {
+ args.add(param.getMainJar().getRes());
+ }
+
+
+ // --files --conf --libjar ...
+ if (StringUtils.isNotEmpty(param.getOthers())) {
+ String others = param.getOthers();
+ if(!others.contains("--queue")){
+ if (StringUtils.isNotEmpty(param.getQueue())) {
+ args.add(Constants.SPARK_QUEUE);
+ args.add(param.getQueue());
+ }
+ }
+ args.add(param.getOthers());
+ }else if (StringUtils.isNotEmpty(param.getQueue())) {
+ args.add(Constants.SPARK_QUEUE);
+ args.add(param.getQueue());
+
+ }
+
+ if (StringUtils.isNotEmpty(param.getMainArgs())) {
+ args.add(param.getMainArgs());
+ }
+
+ return args;
+ }
+
+}
diff --git a/escheduler-server/src/main/java/cn/escheduler/server/worker/task/AbstractTask.java b/escheduler-server/src/main/java/cn/escheduler/server/worker/task/AbstractTask.java
index 213f4fd3f9..6472873d8b 100644
--- a/escheduler-server/src/main/java/cn/escheduler/server/worker/task/AbstractTask.java
+++ b/escheduler-server/src/main/java/cn/escheduler/server/worker/task/AbstractTask.java
@@ -22,6 +22,7 @@ import cn.escheduler.common.enums.TaskRecordStatus;
import cn.escheduler.common.enums.TaskType;
import cn.escheduler.common.process.Property;
import cn.escheduler.common.task.AbstractParameters;
+import cn.escheduler.common.task.flink.FlinkParameters;
import cn.escheduler.common.task.mr.MapreduceParameters;
import cn.escheduler.common.task.procedure.ProcedureParameters;
import cn.escheduler.common.task.python.PythonParameters;
@@ -178,6 +179,8 @@ public abstract class AbstractTask {
case SPARK:
paramsClass = SparkParameters.class;
break;
+ case FLINK:
+ paramsClass = FlinkParameters.class;
case PYTHON:
paramsClass = PythonParameters.class;
break;
diff --git a/escheduler-server/src/main/java/cn/escheduler/server/worker/task/TaskManager.java b/escheduler-server/src/main/java/cn/escheduler/server/worker/task/TaskManager.java
index e23a29ae08..986a6179c9 100644
--- a/escheduler-server/src/main/java/cn/escheduler/server/worker/task/TaskManager.java
+++ b/escheduler-server/src/main/java/cn/escheduler/server/worker/task/TaskManager.java
@@ -19,6 +19,7 @@ package cn.escheduler.server.worker.task;
import cn.escheduler.common.enums.TaskType;
import cn.escheduler.server.worker.task.dependent.DependentTask;
+import cn.escheduler.server.worker.task.flink.FlinkTask;
import cn.escheduler.server.worker.task.mr.MapReduceTask;
import cn.escheduler.server.worker.task.processdure.ProcedureTask;
import cn.escheduler.server.worker.task.python.PythonTask;
@@ -55,6 +56,8 @@ public class TaskManager {
return new MapReduceTask(props, logger);
case SPARK:
return new SparkTask(props, logger);
+ case FLINK:
+ return new FlinkTask(props, logger);
case PYTHON:
return new PythonTask(props, logger);
case DEPENDENT:
diff --git a/escheduler-server/src/main/java/cn/escheduler/server/worker/task/flink/FlinkTask.java b/escheduler-server/src/main/java/cn/escheduler/server/worker/task/flink/FlinkTask.java
new file mode 100644
index 0000000000..bf6f0cc9fb
--- /dev/null
+++ b/escheduler-server/src/main/java/cn/escheduler/server/worker/task/flink/FlinkTask.java
@@ -0,0 +1,118 @@
+/*
+ * 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 cn.escheduler.server.worker.task.flink;
+
+import cn.escheduler.common.process.Property;
+import cn.escheduler.common.task.AbstractParameters;
+import cn.escheduler.common.task.flink.FlinkParameters;
+import cn.escheduler.common.utils.JSONUtils;
+import cn.escheduler.common.utils.ParameterUtils;
+import cn.escheduler.dao.model.ProcessInstance;
+import cn.escheduler.server.utils.FlinkArgsUtils;
+import cn.escheduler.server.utils.ParamUtils;
+import cn.escheduler.server.worker.task.AbstractYarnTask;
+import cn.escheduler.server.worker.task.TaskProps;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * flink task
+ */
+public class FlinkTask extends AbstractYarnTask {
+
+ /**
+ * flink command
+ */
+ private static final String FLINK_COMMAND = "flink";
+ private static final String FLINK_RUN = "run";
+
+ /**
+ * flink parameters
+ */
+ private FlinkParameters flinkParameters;
+
+ public FlinkTask(TaskProps props, Logger logger) {
+ super(props, logger);
+ }
+
+ @Override
+ public void init() {
+
+ logger.info("flink task params {}", taskProps.getTaskParams());
+
+ flinkParameters = JSONUtils.parseObject(taskProps.getTaskParams(), FlinkParameters.class);
+
+ if (!flinkParameters.checkParameters()) {
+ throw new RuntimeException("flink task params is not valid");
+ }
+ flinkParameters.setQueue(taskProps.getQueue());
+
+ if (StringUtils.isNotEmpty(flinkParameters.getMainArgs())) {
+ String args = flinkParameters.getMainArgs();
+ // get process instance by task instance id
+ ProcessInstance processInstance = processDao.findProcessInstanceByTaskId(taskProps.getTaskInstId());
+
+ /**
+ * combining local and global parameters
+ */
+ Map paramsMap = ParamUtils.convert(taskProps.getUserDefParamsMap(),
+ taskProps.getDefinedParams(),
+ flinkParameters.getLocalParametersMap(),
+ processInstance.getCmdTypeIfComplement(),
+ processInstance.getScheduleTime());
+
+ logger.info("param Map : {}", paramsMap);
+ if (paramsMap != null ){
+
+ args = ParameterUtils.convertParameterPlaceholders(args, ParamUtils.convert(paramsMap));
+ logger.info("param args : {}", args);
+ }
+ flinkParameters.setMainArgs(args);
+ }
+ }
+
+ /**
+ * create command
+ * @return
+ */
+ @Override
+ protected String buildCommand() {
+ List args = new ArrayList<>();
+
+ args.add(FLINK_COMMAND);
+ args.add(FLINK_RUN);
+ logger.info("flink task args : {}", args);
+ // other parameters
+ args.addAll(FlinkArgsUtils.buildArgs(flinkParameters));
+
+ String command = ParameterUtils
+ .convertParameterPlaceholders(String.join(" ", args), taskProps.getDefinedParams());
+
+ logger.info("flink task command : {}", command);
+
+ return command;
+ }
+
+ @Override
+ public AbstractParameters getParameters() {
+ return flinkParameters;
+ }
+}
diff --git a/escheduler-ui/src/js/conf/home/pages/dag/_source/config.js b/escheduler-ui/src/js/conf/home/pages/dag/_source/config.js
index 9c1065870f..5305bf7476 100644
--- a/escheduler-ui/src/js/conf/home/pages/dag/_source/config.js
+++ b/escheduler-ui/src/js/conf/home/pages/dag/_source/config.js
@@ -260,6 +260,10 @@ let tasksType = {
desc: 'SPARK',
color: '#E46F13'
},
+ 'FLINK': {
+ desc: 'FLINK',
+ color: '#E46F13'
+ },
'MR': {
desc: 'MapReduce',
color: '#A0A5CC'
diff --git a/escheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss b/escheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss
index 95592e0754..37d3acaa19 100644
--- a/escheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss
+++ b/escheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss
@@ -70,6 +70,9 @@
.icos-SPARK {
background: url("../img/toolbar_SPARK.png") no-repeat 50% 50%;
}
+ .icos-FLINK {
+ background: url("../img/toobar_flink.svg") no-repeat 50% 50%;
+ }
.icos-MR {
background: url("../img/toolbar_MR.png") no-repeat 50% 50%;
}
diff --git a/escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue b/escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue
index 863a44abf5..a46b894d11 100644
--- a/escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue
+++ b/escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue
@@ -19,13 +19,13 @@
+ type="text"
+ v-model="name"
+ :disabled="isDetails"
+ :placeholder="$t('Please enter name(required)')"
+ maxlength="100"
+ @on-blur="_verifName()"
+ autocomplete="off">
@@ -52,13 +52,13 @@
+ resize
+ :autosize="{minRows:2}"
+ type="textarea"
+ :disabled="isDetails"
+ v-model="desc"
+ :placeholder="$t('Please enter description')"
+ autocomplete="off">
@@ -96,68 +96,74 @@
+ ref="timeout"
+ :backfill-item="backfillItem"
+ @on-timeout="_onTimeout">
+ v-if="taskType === 'SHELL'"
+ @on-params="_onParams"
+ ref="SHELL"
+ :backfill-item="backfillItem">
+ v-if="taskType === 'SUB_PROCESS'"
+ @on-params="_onParams"
+ @on-set-process-name="_onSetProcessName"
+ ref="SUB_PROCESS"
+ :backfill-item="backfillItem">
+ v-if="taskType === 'PROCEDURE'"
+ @on-params="_onParams"
+ ref="PROCEDURE"
+ :backfill-item="backfillItem">
+ v-if="taskType === 'SQL'"
+ @on-params="_onParams"
+ ref="SQL"
+ :create-node-id="id"
+ :backfill-item="backfillItem">
+ v-if="taskType === 'SPARK'"
+ @on-params="_onParams"
+ ref="SPARK"
+ :backfill-item="backfillItem">
+
+
+ v-if="taskType === 'MR'"
+ @on-params="_onParams"
+ ref="MR"
+ :backfill-item="backfillItem">
+ v-if="taskType === 'PYTHON'"
+ @on-params="_onParams"
+ ref="PYTHON"
+ :backfill-item="backfillItem">
+ v-if="taskType === 'DEPENDENT'"
+ @on-dependent="_onDependent"
+ ref="DEPENDENT"
+ :backfill-item="backfillItem">
@@ -178,6 +184,7 @@
import i18n from '@/module/i18n'
import mShell from './tasks/shell'
import mSpark from './tasks/spark'
+ import mFlink from './tasks/flink'
import mPython from './tasks/python'
import JSP from './../plugIn/jsPlumbHandle'
import mProcedure from './tasks/procedure'
@@ -284,12 +291,12 @@
}
this.store.dispatch('dag/getSubProcessId', { taskId: stateId }).then(res => {
this.$emit('onSubProcess', {
- subProcessId: res.data.subProcessInstanceId,
- fromThis: this
- })
- }).catch(e => {
- this.$message.error(e.msg || '')
+ subProcessId: res.data.subProcessInstanceId,
+ fromThis: this
})
+ }).catch(e => {
+ this.$message.error(e.msg || '')
+ })
} else {
this.$emit('onSubProcess', {
subProcessId: this.backfillItem.params.processDefinitionId,
@@ -413,10 +420,10 @@
if (taskList.length) {
taskList.forEach(v => {
if (v.id === this.id) {
- o = v
- this.backfillItem = v
- }
- })
+ o = v
+ this.backfillItem = v
+ }
+ })
// Non-null objects represent backfill
if (!_.isEmpty(o)) {
this.name = o.name
@@ -455,6 +462,7 @@
mSql,
mLog,
mSpark,
+ mFlink,
mPython,
mDependent,
mSelectInput,
diff --git a/escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue b/escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue
new file mode 100644
index 0000000000..1c3b18a64c
--- /dev/null
+++ b/escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue
@@ -0,0 +1,388 @@
+
+
+
+ {{$t('Program Type')}}
+
+
+
+
+
+
+
+
+
+ {{$t('Main class')}}
+
+
+
+
+
+
+ {{$t('Main jar package')}}
+
+
+
+
+
+
+
+
+ {{$t('Deploy Mode')}}
+
+
+
+
+
+
+
+
+ {{$t('slot')}}
+
+
+
+
+ {{$t('taskManager')}}
+
+
+
+
+
+
+ {{$t('jobManagerMemory')}}
+
+
+
+
+ {{$t('taskManagerMemory')}}
+
+
+
+
+
+
+
+
+ {{$t('Command-line parameters')}}
+
+
+
+
+
+
+ {{$t('Other parameters')}}
+
+
+
+
+
+
+ {{$t('Resources')}}
+
+
+
+
+
+
+ {{$t('Custom Parameters')}}
+
+
+
+
+
+
+
+
+
+
diff --git a/escheduler-ui/src/js/conf/home/pages/dag/img/toobar_flink.svg b/escheduler-ui/src/js/conf/home/pages/dag/img/toobar_flink.svg
new file mode 100644
index 0000000000..33ba8b7b3d
--- /dev/null
+++ b/escheduler-ui/src/js/conf/home/pages/dag/img/toobar_flink.svg
@@ -0,0 +1,211 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/escheduler-ui/src/js/module/i18n/locale/zh_CN.js b/escheduler-ui/src/js/module/i18n/locale/zh_CN.js
index 7ac3dda87e..cfa0224185 100644
--- a/escheduler-ui/src/js/module/i18n/locale/zh_CN.js
+++ b/escheduler-ui/src/js/module/i18n/locale/zh_CN.js
@@ -476,5 +476,9 @@ export default {
'warning of timeout': '超时告警',
'Next five execution times': '接下来五次执行时间',
'Execute time': '执行时间',
- 'Complement range': '补数范围'
+ 'Complement range': '补数范围',
+ 'slot':'slot数量',
+ 'taskManager':'taskManage数量',
+ 'jobManagerMemory':'jobManager内存数',
+ 'taskManagerMemory':'taskManager内存数'
}
diff --git a/escheduler-ui/src/view/docs/zh_CN/_book/images/flink_edit.png b/escheduler-ui/src/view/docs/zh_CN/_book/images/flink_edit.png
new file mode 100644
index 0000000000000000000000000000000000000000..b7c232115753ed31d72cf869dff8859ca717ddf9
GIT binary patch
literal 123946
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