diff --git a/pom.xml b/pom.xml
index 99022ea4..24f4c25b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,8 +40,9 @@
powerjob-server
powerjob-common
powerjob-client
- powerjob-worker-samples
powerjob-worker-agent
+ powerjob-worker-spring-boot-starter
+ powerjob-worker-samples
diff --git a/powerjob-client/pom.xml b/powerjob-client/pom.xml
index 39ee4363..2d4286da 100644
--- a/powerjob-client/pom.xml
+++ b/powerjob-client/pom.xml
@@ -10,11 +10,11 @@
4.0.0
powerjob-client
- 3.2.0
+ 3.2.1
jar
- 3.2.0
+ 3.2.1
5.6.1
diff --git a/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/OhMyClient.java b/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/OhMyClient.java
index 54d00ad5..1b0d66d7 100644
--- a/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/OhMyClient.java
+++ b/powerjob-client/src/main/java/com/github/kfcfans/powerjob/client/OhMyClient.java
@@ -6,6 +6,7 @@ import com.github.kfcfans.powerjob.common.OpenAPIConstant;
import com.github.kfcfans.powerjob.common.request.http.SaveJobInfoRequest;
import com.github.kfcfans.powerjob.common.request.http.SaveWorkflowRequest;
import com.github.kfcfans.powerjob.common.response.*;
+import com.github.kfcfans.powerjob.common.utils.CommonUtils;
import com.github.kfcfans.powerjob.common.utils.HttpUtils;
import com.github.kfcfans.powerjob.common.utils.JsonUtils;
import com.google.common.collect.Lists;
@@ -31,13 +32,13 @@ public class OhMyClient {
private Long appId;
private String currentAddress;
- private List allAddress;
+ private final List allAddress;
private static final String URL_PATTERN = "http://%s%s%s";
/**
* 初始化 OhMyClient 客户端
- * @param domain www.oms-server.com(内网域名,自行完成DNS & Proxy)
+ * @param domain 比如 www.powerjob-server.com(内网域名,自行完成 DNS & Proxy)
* @param appName 负责的应用名称
*/
public OhMyClient(String domain, String appName, String password) {
@@ -52,8 +53,8 @@ public class OhMyClient {
*/
public OhMyClient(List addressList, String appName, String password) {
- Objects.requireNonNull(addressList, "domain can't be null!");
- Objects.requireNonNull(appName, "appName can't be null");
+ CommonUtils.requireNonNull(addressList, "domain can't be null!");
+ CommonUtils.requireNonNull(appName, "appName can't be null");
allAddress = addressList;
for (String addr : addressList) {
@@ -77,7 +78,7 @@ public class OhMyClient {
if (StringUtils.isEmpty(currentAddress)) {
throw new OmsException("no server available");
}
- log.info("[OhMyClient] {}'s oms-client bootstrap successfully.", appName);
+ log.info("[OhMyClient] {}'s oms-client bootstrap successfully, using server: {}", appName, currentAddress);
}
private static String assertApp(String appName, String password, String url) throws IOException {
@@ -211,6 +212,22 @@ public class OhMyClient {
return JsonUtils.parseObject(post, ResultDTO.class);
}
+ /**
+ * 取消任务实例
+ * 接口使用条件:调用接口时间与待取消任务的预计执行时间有一定时间间隔,否则不保证可靠性!
+ * @param instanceId 任务实例ID
+ * @return true 代表取消成功,false 取消失败
+ * @throws Exception 异常
+ */
+ public ResultDTO cancelInstance(Long instanceId) throws Exception {
+ RequestBody body = new FormBody.Builder()
+ .add("instanceId", instanceId.toString())
+ .add("appId", appId.toString())
+ .build();
+ String post = postHA(OpenAPIConstant.CANCEL_INSTANCE, body);
+ return JsonUtils.parseObject(post, ResultDTO.class);
+ }
+
/**
* 查询任务实例状态
* @param instanceId 应用实例ID
@@ -364,28 +381,35 @@ public class OhMyClient {
private String postHA(String path, RequestBody requestBody) {
// 先尝试默认地址
+ String url = getUrl(path, currentAddress);
try {
- String res = HttpUtils.post(getUrl(path, currentAddress), requestBody);
+ String res = HttpUtils.post(url, requestBody);
if (StringUtils.isNotEmpty(res)) {
return res;
}
- }catch (Exception ignore) {
+ }catch (Exception e) {
+ log.warn("[OhMyClient] request url:{} failed, reason is {}.", url, e.toString());
}
// 失败,开始重试
for (String addr : allAddress) {
+ if (Objects.equals(addr, currentAddress)) {
+ continue;
+ }
+ url = getUrl(path, addr);
try {
- String res = HttpUtils.post(getUrl(path, addr), requestBody);
+ String res = HttpUtils.post(url, requestBody);
if (StringUtils.isNotEmpty(res)) {
log.warn("[OhMyClient] server change: from({}) -> to({}).", currentAddress, addr);
currentAddress = addr;
return res;
}
- }catch (Exception ignore) {
+ }catch (Exception e) {
+ log.warn("[OhMyClient] request url:{} failed, reason is {}.", url, e.toString());
}
}
- log.error("[OhMyClient] no server available in {}.", allAddress);
+ log.error("[OhMyClient] do post for path: {} failed because of no server available in {}.", path, allAddress);
throw new OmsException("no server available");
}
}
diff --git a/powerjob-client/src/test/java/TestClient.java b/powerjob-client/src/test/java/TestClient.java
index f1f7dec8..b4d00ae8 100644
--- a/powerjob-client/src/test/java/TestClient.java
+++ b/powerjob-client/src/test/java/TestClient.java
@@ -9,6 +9,8 @@ import com.github.kfcfans.powerjob.common.utils.JsonUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import java.util.concurrent.TimeUnit;
+
/**
* 测试 Client
*
@@ -87,4 +89,24 @@ public class TestClient {
public void testFetchInstanceStatus() throws Exception {
System.out.println(ohMyClient.fetchInstanceStatus(141251409466097728L));
}
+
+ @Test
+ public void testCancelInstanceInTimeWheel() throws Exception {
+ ResultDTO startRes = ohMyClient.runJob(15L, "start by OhMyClient", 20000);
+ System.out.println("runJob result: " + JsonUtils.toJSONString(startRes));
+ ResultDTO cancelRes = ohMyClient.cancelInstance(startRes.getData());
+ System.out.println("cancelJob result: " + JsonUtils.toJSONString(cancelRes));
+ }
+
+ @Test
+ public void testCancelInstanceInDatabase() throws Exception {
+ ResultDTO startRes = ohMyClient.runJob(15L, "start by OhMyClient", 2000000);
+ System.out.println("runJob result: " + JsonUtils.toJSONString(startRes));
+
+ // 手动重启 server,干掉时间轮中的调度数据
+ TimeUnit.MINUTES.sleep(1);
+
+ ResultDTO cancelRes = ohMyClient.cancelInstance(startRes.getData());
+ System.out.println("cancelJob result: " + JsonUtils.toJSONString(cancelRes));
+ }
}
diff --git a/powerjob-common/pom.xml b/powerjob-common/pom.xml
index 3e8766b4..bca0ae69 100644
--- a/powerjob-common/pom.xml
+++ b/powerjob-common/pom.xml
@@ -10,7 +10,7 @@
4.0.0
powerjob-common
- 3.2.0
+ 3.2.1
jar
diff --git a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/InstanceStatus.java b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/InstanceStatus.java
index 749926db..536ef621 100644
--- a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/InstanceStatus.java
+++ b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/InstanceStatus.java
@@ -21,6 +21,7 @@ public enum InstanceStatus {
RUNNING(3, "运行中"),
FAILED(4, "失败"),
SUCCEED(5, "成功"),
+ CANCELED(9, "取消"),
STOPPED(10, "手动停止");
private int v;
@@ -29,7 +30,7 @@ public enum InstanceStatus {
// 广义的运行状态
public static final List generalizedRunningStatus = Lists.newArrayList(WAITING_DISPATCH.v, WAITING_WORKER_RECEIVE.v, RUNNING.v);
// 结束状态
- public static final List finishedStatus = Lists.newArrayList(FAILED.v, SUCCEED.v, STOPPED.v);
+ public static final List finishedStatus = Lists.newArrayList(FAILED.v, SUCCEED.v, CANCELED.v, STOPPED.v);
public static InstanceStatus of(int v) {
for (InstanceStatus is : values()) {
diff --git a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/OpenAPIConstant.java b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/OpenAPIConstant.java
index 177b355c..82477591 100644
--- a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/OpenAPIConstant.java
+++ b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/OpenAPIConstant.java
@@ -22,6 +22,7 @@ public class OpenAPIConstant {
/* ************* Instance 区 ************* */
public static final String STOP_INSTANCE = "/stopInstance";
+ public static final String CANCEL_INSTANCE = "/cancelInstance";
public static final String FETCH_INSTANCE_STATUS = "/fetchInstanceStatus";
public static final String FETCH_INSTANCE_INFO = "/fetchInstanceInfo";
diff --git a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/SystemInstanceResult.java b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/SystemInstanceResult.java
index 5dde06cb..0682a94d 100644
--- a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/SystemInstanceResult.java
+++ b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/SystemInstanceResult.java
@@ -30,6 +30,7 @@ public class SystemInstanceResult {
// 被用户手动停止
public static final String STOPPED_BY_USER = "stopped by user";
+ public static final String CANCELED_BY_USER = "canceled by user";
}
diff --git a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/model/InstanceDetail.java b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/model/InstanceDetail.java
index efa4686f..6706bca0 100644
--- a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/model/InstanceDetail.java
+++ b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/model/InstanceDetail.java
@@ -16,6 +16,8 @@ import java.util.List;
@NoArgsConstructor
public class InstanceDetail implements OmsSerializable {
+ // 任务预计执行时间
+ private Long expectedTriggerTime;
// 任务整体开始时间
private Long actualTriggerTime;
// 任务整体结束时间(可能不存在)
diff --git a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/utils/HttpUtils.java b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/utils/HttpUtils.java
index 3612f179..21664614 100644
--- a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/utils/HttpUtils.java
+++ b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/utils/HttpUtils.java
@@ -17,7 +17,7 @@ import java.util.concurrent.TimeUnit;
*/
public class HttpUtils {
- private static OkHttpClient client;
+ private static final OkHttpClient client;
private static final int HTTP_SUCCESS_CODE = 200;
static {
diff --git a/powerjob-server/pom.xml b/powerjob-server/pom.xml
index 86e187f4..dc745cf1 100644
--- a/powerjob-server/pom.xml
+++ b/powerjob-server/pom.xml
@@ -10,13 +10,13 @@
4.0.0
powerjob-server
- 3.2.0
+ 3.2.1
jar
2.9.2
2.2.6.RELEASE
- 3.2.0
+ 3.2.1
8.0.19
1.4.200
2.5.2
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/OhMyApplication.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/OhMyApplication.java
index 3d35a2d7..686a4c60 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/OhMyApplication.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/OhMyApplication.java
@@ -1,27 +1,59 @@
package com.github.kfcfans.powerjob.server;
import com.github.kfcfans.powerjob.server.akka.OhMyServer;
+import com.github.kfcfans.powerjob.server.common.utils.OmsFileUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
+import java.io.File;
+
/**
* SpringBoot 启动入口
*
* @author tjq
* @since 2020/3/29
*/
+@Slf4j
@EnableScheduling
@SpringBootApplication
public class OhMyApplication {
+ private static final String TIPS = "\n\n" +
+ "******************* PowerJob Tips *******************\n" +
+ "如果应用无法启动,我们建议您仔细阅读以下文档来解决:\n" +
+ "if server can't startup, we recommend that you read the documentation to find a solution:\n" +
+ "https://www.yuque.com/powerjob/guidence/xp5ygc#xMQC9\n" +
+ "******************* PowerJob Tips *******************\n\n";
+
public static void main(String[] args) {
+ // 完成前置工作
+ pre();
+
// 先启动 ActorSystem
OhMyServer.init();
// 再启动SpringBoot
- SpringApplication.run(OhMyApplication.class, args);
+ try {
+ SpringApplication.run(OhMyApplication.class, args);
+ }catch (Throwable t) {
+ log.error(TIPS);
+ throw t;
+ }
+ }
+
+ private static void pre() {
+ log.info(TIPS);
+
+ // 删除历史遗留的 H2 数据库文件
+ try {
+ FileUtils.forceDeleteOnExit(new File(OmsFileUtils.genH2Path()));
+ }catch (Exception e) {
+ log.warn("[PowerJob] delete h2 workspace({}) failed, if server can't startup successfully, please delete it manually", OmsFileUtils.genH2Path(), e);
+ }
}
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/OmsFileUtils.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/OmsFileUtils.java
index 147d475d..1f5a0f76 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/OmsFileUtils.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/OmsFileUtils.java
@@ -53,6 +53,14 @@ public class OmsFileUtils {
return genTemporaryPath() + uuid + "/";
}
+ /**
+ * 获取 H2 数据库工作目录
+ * @return H2 工作目录
+ */
+ public static String genH2Path() {
+ return COMMON_PATH + "h2/";
+ }
+
/**
* 将文本写入文件
* @param content 文本内容
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/timewheel/HashedWheelTimer.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/timewheel/HashedWheelTimer.java
index b1077bb1..26036070 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/timewheel/HashedWheelTimer.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/timewheel/HashedWheelTimer.java
@@ -30,7 +30,7 @@ public class HashedWheelTimer implements Timer {
private final Indicator indicator;
- private long startTime;
+ private final long startTime;
private final Queue waitingTasks = Queues.newLinkedBlockingQueue();
private final Queue canceledTasks = Queues.newLinkedBlockingQueue();
@@ -184,7 +184,6 @@ public class HashedWheelTimer implements Timer {
log.warn("[HashedWheelTimer] timerFuture.totalTicks < currentTick, please fix the bug");
}
- timerFuture.status = HashedWheelTimerFuture.RUNNING;
try {
// 提交执行
runTask(timerFuture);
@@ -202,6 +201,7 @@ public class HashedWheelTimer implements Timer {
}
private void runTask(HashedWheelTimerFuture timerFuture) {
+ timerFuture.status = HashedWheelTimerFuture.RUNNING;
if (taskProcessPool == null) {
timerFuture.timerTask.run();
}else {
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/config/MultiDatasourceConfig.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/config/MultiDatasourceConfig.java
index c2beeb49..f233bc99 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/config/MultiDatasourceConfig.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/config/MultiDatasourceConfig.java
@@ -1,5 +1,6 @@
package com.github.kfcfans.powerjob.server.persistence.config;
+import com.github.kfcfans.powerjob.server.common.utils.OmsFileUtils;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -19,7 +20,10 @@ import javax.sql.DataSource;
@Configuration
public class MultiDatasourceConfig {
- private static final String H2_JDBC_URL = "jdbc:h2:file:~/powerjob-server/h2/powerjob_server_db";
+ private static final String H2_DRIVER_CLASS_NAME = "org.h2.Driver";
+ private static final String H2_JDBC_URL_PATTERN = "jdbc:h2:file:%spowerjob_server_db";
+ private static final int H2_MIN_SIZE = 4;
+ private static final int H2_MAX_ACTIVE_SIZE = 10;
@Primary
@Bean("omsCoreDatasource")
@@ -30,15 +34,14 @@ public class MultiDatasourceConfig {
@Bean("omsLocalDatasource")
public DataSource initOmsLocalDatasource() {
-
HikariConfig config = new HikariConfig();
- config.setDriverClassName("org.h2.Driver");
- config.setJdbcUrl(H2_JDBC_URL);
+ config.setDriverClassName(H2_DRIVER_CLASS_NAME);
+ config.setJdbcUrl(String.format(H2_JDBC_URL_PATTERN, OmsFileUtils.genH2Path()));
config.setAutoCommit(true);
// 池中最小空闲连接数量
- config.setMinimumIdle(4);
+ config.setMinimumIdle(H2_MIN_SIZE);
// 池中最大连接数量
- config.setMaximumPoolSize(32);
+ config.setMaximumPoolSize(H2_MAX_ACTIVE_SIZE);
return new HikariDataSource(config);
}
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/DispatchService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/DispatchService.java
index 13281259..3c621821 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/DispatchService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/DispatchService.java
@@ -66,17 +66,27 @@ public class DispatchService {
Date now = new Date();
String dbInstanceParams = instanceParams == null ? "" : instanceParams;
+ // 检查当前任务是否被取消
+ InstanceInfoDO instanceInfo = instanceInfoRepository.findByInstanceId(instanceId);
+ InstanceStatus currentStatus = InstanceStatus.of(instanceInfo.getStatus());
+ if (currentStatus != WAITING_DISPATCH) {
+ log.info("[Dispatcher-{}|{}] cancel dispatch job due to instance status({}) is not WAITING_DISPATCH", jobId, instanceId, currentStatus.name());
+ return;
+ }
+
// 查询当前运行的实例数
long current = System.currentTimeMillis();
// 0 代表不限制在线任务,还能省去一次 DB 查询
- if (jobInfo.getMaxInstanceNum() > 0) {
+ Integer maxInstanceNum = jobInfo.getMaxInstanceNum();
+ if (maxInstanceNum > 0) {
+ // 这个 runningInstanceCount 已经包含了本 instance
long runningInstanceCount = instanceInfoRepository.countByJobIdAndStatusIn(jobId, Lists.newArrayList(WAITING_WORKER_RECEIVE.getV(), RUNNING.getV()));
// 超出最大同时运行限制,不执行调度
- if (runningInstanceCount > jobInfo.getMaxInstanceNum()) {
- String result = String.format(SystemInstanceResult.TOO_MUCH_INSTANCE, runningInstanceCount, jobInfo.getMaxInstanceNum());
- log.warn("[Dispatcher-{}|{}] cancel dispatch job due to too much instance(num={}) is running.", jobId, instanceId, runningInstanceCount);
+ if (runningInstanceCount > maxInstanceNum) {
+ String result = String.format(SystemInstanceResult.TOO_MUCH_INSTANCE, runningInstanceCount, maxInstanceNum);
+ log.warn("[Dispatcher-{}|{}] cancel dispatch job due to too much instance is running ({} > {}).", jobId, instanceId, runningInstanceCount, maxInstanceNum);
instanceInfoRepository.update4TriggerFailed(instanceId, FAILED.getV(), currentRunningTimes, current, current, RemoteConstant.EMPTY_ADDRESS, result, dbInstanceParams, now);
instanceManager.processFinishedInstance(instanceId, wfInstanceId, FAILED, result);
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/JobService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/JobService.java
index b485edf2..9b3810e8 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/JobService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/JobService.java
@@ -12,7 +12,7 @@ import com.github.kfcfans.powerjob.server.persistence.core.model.JobInfoDO;
import com.github.kfcfans.powerjob.server.persistence.core.repository.InstanceInfoRepository;
import com.github.kfcfans.powerjob.server.persistence.core.repository.JobInfoRepository;
import com.github.kfcfans.powerjob.server.service.instance.InstanceService;
-import com.github.kfcfans.powerjob.server.service.timing.schedule.HashedWheelTimerHolder;
+import com.github.kfcfans.powerjob.server.service.instance.InstanceTimeWheelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@@ -22,7 +22,6 @@ import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Optional;
-import java.util.concurrent.TimeUnit;
/**
* 任务服务
@@ -103,6 +102,8 @@ public class JobService {
*/
public long runJob(Long jobId, String instanceParams, long delay) {
+ log.info("[Job-{}] try to run job, instanceParams={},delay={} ms.", jobId, instanceParams, delay);
+
JobInfoDO jobInfo = jobInfoRepository.findById(jobId).orElseThrow(() -> new IllegalArgumentException("can't find job by id:" + jobId));
Long instanceId = instanceService.create(jobInfo.getId(), jobInfo.getAppId(), instanceParams, null, System.currentTimeMillis() + Math.max(delay, 0));
instanceInfoRepository.flush();
@@ -110,10 +111,11 @@ public class JobService {
if (delay <= 0) {
dispatchService.dispatch(jobInfo, instanceId, 0, instanceParams, null);
}else {
- HashedWheelTimerHolder.TIMER.schedule(() -> {
+ InstanceTimeWheelService.schedule(instanceId, delay, () -> {
dispatchService.dispatch(jobInfo, instanceId, 0, instanceParams, null);
- }, delay, TimeUnit.MILLISECONDS);
+ });
}
+ log.info("[Job-{}] run job successfully, instanceId={}", jobId, instanceId);
return instanceId;
}
@@ -171,7 +173,7 @@ public class JobService {
return;
}
if (executeLogs.size() > 1) {
- log.warn("[JobService] frequent job should just have one running instance, there must have some bug.");
+ log.warn("[Job-{}] frequent job should just have one running instance, there must have some bug.", jobId);
}
executeLogs.forEach(instance -> {
try {
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceManager.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceManager.java
index d6938678..ceda11e4 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceManager.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceManager.java
@@ -107,7 +107,7 @@ public class InstanceManager {
log.info("[InstanceManager-{}] instance execute failed but will take the {}th retry.", instanceId, instanceInfo.getRunningTimes());
// 延迟10S重试(由于重试不改变 instanceId,如果派发到同一台机器,上一个 TaskTracker 还处于资源释放阶段,无法创建新的TaskTracker,任务失败)
- HashedWheelTimerHolder.TIMER.schedule(() -> {
+ HashedWheelTimerHolder.INACCURATE_TIMER.schedule(() -> {
dispatchService.redispatch(jobInfo, instanceId, instanceInfo.getRunningTimes());
}, 10, TimeUnit.SECONDS);
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceService.java
index c152a321..97a21848 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceService.java
@@ -3,6 +3,7 @@ package com.github.kfcfans.powerjob.server.service.instance;
import akka.actor.ActorSelection;
import akka.pattern.Patterns;
import com.github.kfcfans.powerjob.common.InstanceStatus;
+import com.github.kfcfans.powerjob.common.OmsException;
import com.github.kfcfans.powerjob.common.RemoteConstant;
import com.github.kfcfans.powerjob.common.SystemInstanceResult;
import com.github.kfcfans.powerjob.common.model.InstanceDetail;
@@ -12,6 +13,7 @@ import com.github.kfcfans.powerjob.common.response.AskResponse;
import com.github.kfcfans.powerjob.common.response.InstanceInfoDTO;
import com.github.kfcfans.powerjob.server.akka.OhMyServer;
import com.github.kfcfans.powerjob.server.common.constans.InstanceType;
+import com.github.kfcfans.powerjob.server.common.utils.timewheel.TimerFuture;
import com.github.kfcfans.powerjob.server.persistence.core.model.InstanceInfoDO;
import com.github.kfcfans.powerjob.server.persistence.core.repository.InstanceInfoRepository;
import com.github.kfcfans.powerjob.server.service.id.IdGenerateService;
@@ -86,12 +88,7 @@ public class InstanceService {
log.info("[Instance-{}] try to stop the instance.", instanceId);
try {
- InstanceInfoDO instanceInfo = instanceInfoRepository.findByInstanceId(instanceId);
- if (instanceInfo == null) {
- log.warn("[Instance-{}] can't find instanceInfo by instanceId.", instanceId);
- throw new IllegalArgumentException("invalid instanceId: " + instanceId);
- }
-
+ InstanceInfoDO instanceInfo = fetchInstanceInfo(instanceId);
// 判断状态,只有运行中才能停止
if (!InstanceStatus.generalizedRunningStatus.contains(instanceInfo.getStatus())) {
throw new IllegalArgumentException("can't stop finished instance!");
@@ -124,17 +121,53 @@ public class InstanceService {
}
}
+ /**
+ * 取消任务实例的运行
+ * 接口使用条件:调用接口时间与待取消任务的预计执行时间有一定时间间隔,否则不保证可靠性!
+ * @param instanceId 任务实例
+ */
+ public void cancelInstance(Long instanceId) {
+ log.info("[Instance-{}] try to cancel the instance.", instanceId);
+
+ try {
+ InstanceInfoDO instanceInfo = fetchInstanceInfo(instanceId);
+ TimerFuture timerFuture = InstanceTimeWheelService.fetchTimerFuture(instanceId);
+
+ boolean success;
+ // 本机时间轮中存在该任务且顺利取消,抢救成功!
+ if (timerFuture != null) {
+ success = timerFuture.cancel();
+ } else {
+ // 调用该接口时间和预计调度时间相近时,理论上会出现问题,cancel 状态还没写进去另一边就完成了 dispatch,随后状态会被覆盖
+ // 解决该问题的成本极高(分布式锁),因此选择不解决
+ // 该接口使用条件:调用接口时间与待取消任务的预计执行时间有一定时间间隔,否则不保证可靠性
+ success = InstanceStatus.WAITING_DISPATCH.getV() == instanceInfo.getStatus();
+ }
+
+ if (success) {
+ instanceInfo.setStatus(InstanceStatus.CANCELED.getV());
+ instanceInfo.setResult(SystemInstanceResult.CANCELED_BY_USER);
+ // 如果写 DB 失败,抛异常,接口返回 false,即取消失败,任务会被 HA 机制重新调度执行,因此此处不需要任何处理
+ instanceInfoRepository.saveAndFlush(instanceInfo);
+ log.info("[Instance-{}] cancel the instance successfully.", instanceId);
+ }else {
+ log.warn("[Instance-{}] cancel the instance failed.", instanceId);
+ throw new OmsException("instance already up and running");
+ }
+
+ }catch (Exception e) {
+ log.error("[Instance-{}] cancelInstance failed.", instanceId, e);
+ throw e;
+ }
+ }
+
/**
* 获取任务实例的信息
* @param instanceId 任务实例ID
* @return 任务实例的信息
*/
public InstanceInfoDTO getInstanceInfo(Long instanceId) {
- InstanceInfoDO instanceInfoDO = instanceInfoRepository.findByInstanceId(instanceId);
- if (instanceInfoDO == null) {
- log.warn("[Instance-{}] can't find InstanceInfo by instanceId.", instanceId);
- throw new IllegalArgumentException("invalid instanceId: " + instanceId);
- }
+ InstanceInfoDO instanceInfoDO = fetchInstanceInfo(instanceId);
InstanceInfoDTO instanceInfoDTO = new InstanceInfoDTO();
BeanUtils.copyProperties(instanceInfoDO, instanceInfoDTO);
return instanceInfoDTO;
@@ -146,11 +179,7 @@ public class InstanceService {
* @return 任务实例的状态
*/
public InstanceStatus getInstanceStatus(Long instanceId) {
- InstanceInfoDO instanceInfoDO = instanceInfoRepository.findByInstanceId(instanceId);
- if (instanceInfoDO == null) {
- log.warn("[Instance-{}] can't find InstanceInfo by instanceId.", instanceId);
- throw new IllegalArgumentException("invalid instanceId: " + instanceId);
- }
+ InstanceInfoDO instanceInfoDO = fetchInstanceInfo(instanceId);
return InstanceStatus.of(instanceInfoDO.getStatus());
}
@@ -161,11 +190,7 @@ public class InstanceService {
*/
public InstanceDetail getInstanceDetail(Long instanceId) {
- InstanceInfoDO instanceInfoDO = instanceInfoRepository.findByInstanceId(instanceId);
- if (instanceInfoDO == null) {
- log.warn("[Instance-{}] can't find InstanceInfo by instanceId", instanceId);
- throw new IllegalArgumentException("invalid instanceId: " + instanceId);
- }
+ InstanceInfoDO instanceInfoDO = fetchInstanceInfo(instanceId);
InstanceStatus instanceStatus = InstanceStatus.of(instanceInfoDO.getStatus());
@@ -202,4 +227,12 @@ public class InstanceService {
return detail;
}
+ private InstanceInfoDO fetchInstanceInfo(Long instanceId) {
+ InstanceInfoDO instanceInfoDO = instanceInfoRepository.findByInstanceId(instanceId);
+ if (instanceInfoDO == null) {
+ log.warn("[Instance-{}] can't find InstanceInfo by instanceId", instanceId);
+ throw new IllegalArgumentException("invalid instanceId: " + instanceId);
+ }
+ return instanceInfoDO;
+ }
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceTimeWheelService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceTimeWheelService.java
new file mode 100644
index 00000000..10a0c9d3
--- /dev/null
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceTimeWheelService.java
@@ -0,0 +1,51 @@
+package com.github.kfcfans.powerjob.server.service.instance;
+
+import com.github.kfcfans.powerjob.server.common.utils.timewheel.HashedWheelTimer;
+import com.github.kfcfans.powerjob.server.common.utils.timewheel.TimerFuture;
+import com.github.kfcfans.powerjob.server.common.utils.timewheel.TimerTask;
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 定时调度任务实例
+ *
+ * @author tjq
+ * @since 2020/7/25
+ */
+public class InstanceTimeWheelService {
+
+ private static final Map CARGO = Maps.newConcurrentMap();
+
+ // 精确时间轮,每 1S 走一格
+ private static final HashedWheelTimer TIMER = new HashedWheelTimer(1, 4096, Runtime.getRuntime().availableProcessors() * 4);
+ // 支持取消的时间间隔,低于该阈值则不会放进 CARGO
+ private static final long MIN_INTERVAL_MS = 1000;
+
+ /**
+ * 定时调度
+ * @param uniqueId 唯一 ID,必须是 snowflake 算法生成的 ID
+ * @param delayMS 延迟毫秒数
+ * @param timerTask 需要执行的目标方法
+ */
+ public static void schedule(Long uniqueId, Long delayMS, TimerTask timerTask) {
+ TimerFuture timerFuture = TIMER.schedule(() -> {
+ CARGO.remove(uniqueId);
+ timerTask.run();
+ }, delayMS, TimeUnit.MILLISECONDS);
+ if (delayMS > MIN_INTERVAL_MS) {
+ CARGO.put(uniqueId, timerFuture);
+ }
+ }
+
+ /**
+ * 获取 TimerFuture
+ * @param uniqueId 唯一 ID
+ * @return TimerFuture
+ */
+ public static TimerFuture fetchTimerFuture(Long uniqueId) {
+ return CARGO.get(uniqueId);
+ }
+
+}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/InstanceStatusCheckService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/InstanceStatusCheckService.java
index ad677415..d568b067 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/InstanceStatusCheckService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/InstanceStatusCheckService.java
@@ -192,6 +192,6 @@ public class InstanceStatusCheckService {
instance.setResult(SystemInstanceResult.REPORT_TIMEOUT);
instanceInfoRepository.saveAndFlush(instance);
- instanceManager.processFinishedInstance(instance.getInstanceId(), instance.getWfInstanceId(), InstanceStatus.FAILED, "timeout, maybe TaskTracker down!");
+ instanceManager.processFinishedInstance(instance.getInstanceId(), instance.getWfInstanceId(), InstanceStatus.FAILED, SystemInstanceResult.REPORT_TIMEOUT);
}
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/HashedWheelTimerHolder.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/HashedWheelTimerHolder.java
index a6667d51..113944b8 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/HashedWheelTimerHolder.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/HashedWheelTimerHolder.java
@@ -10,9 +10,6 @@ import com.github.kfcfans.powerjob.server.common.utils.timewheel.HashedWheelTime
*/
public class HashedWheelTimerHolder {
- // 精确时间轮,每 1S 走一格
- public static final HashedWheelTimer TIMER = new HashedWheelTimer(1, 4096, Runtime.getRuntime().availableProcessors() * 4);
-
// 非精确时间轮,每 5S 走一格
public static final HashedWheelTimer INACCURATE_TIMER = new HashedWheelTimer(5, 16, 0);
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/OmsScheduleService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/OmsScheduleService.java
index d4aa4efd..6e09a62a 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/OmsScheduleService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/OmsScheduleService.java
@@ -16,12 +16,12 @@ import com.github.kfcfans.powerjob.server.service.DispatchService;
import com.github.kfcfans.powerjob.server.service.JobService;
import com.github.kfcfans.powerjob.server.service.ha.WorkerManagerService;
import com.github.kfcfans.powerjob.server.service.instance.InstanceService;
+import com.github.kfcfans.powerjob.server.service.instance.InstanceTimeWheelService;
import com.github.kfcfans.powerjob.server.service.workflow.WorkflowInstanceManager;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
@@ -34,7 +34,6 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@@ -160,9 +159,9 @@ public class OmsScheduleService {
delay = targetTriggerTime - nowTime;
}
- HashedWheelTimerHolder.TIMER.schedule(() -> {
+ InstanceTimeWheelService.schedule(instanceId, delay, () -> {
dispatchService.dispatch(jobInfoDO, instanceId, 0, null, null);
- }, delay, TimeUnit.MILLISECONDS);
+ });
});
// 3. 计算下一次调度时间(忽略5S内的重复执行,即CRON模式下最小的连续执行间隔为 SCHEDULE_RATE ms)
@@ -216,7 +215,7 @@ public class OmsScheduleService {
log.warn("[Workflow-{}] workflow schedule delay, expect:{}, actual: {}", wfInfo.getId(), wfInfo.getNextTriggerTime(), System.currentTimeMillis());
delay = 0;
}
- HashedWheelTimerHolder.TIMER.schedule(() -> workflowInstanceManager.start(wfInfo, wfInstanceId), delay, TimeUnit.MILLISECONDS);
+ InstanceTimeWheelService.schedule(wfInstanceId, delay, () -> workflowInstanceManager.start(wfInfo, wfInstanceId));
// 3. 重新计算下一次调度时间并更新
try {
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowInstanceManager.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowInstanceManager.java
index b5cfbd56..955c831b 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowInstanceManager.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowInstanceManager.java
@@ -204,7 +204,7 @@ public class WorkflowInstanceManager {
node.setStatus(status.getV());
node.setResult(result);
- log.debug("[Workflow-{}|{}] node(jobId={},instanceId={}) finished in workflowInstance, status={},result={}", wfId, wfInstanceId, node.getJobId(), instanceId, status.name(), result);
+ log.info("[Workflow-{}|{}] node(jobId={},instanceId={}) finished in workflowInstance, status={},result={}", wfId, wfInstanceId, node.getJobId(), instanceId, status.name(), result);
}
if (InstanceStatus.generalizedRunningStatus.contains(node.getStatus())) {
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/AppInfoController.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/AppInfoController.java
index eb3f463d..5123c123 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/AppInfoController.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/AppInfoController.java
@@ -41,6 +41,7 @@ public class AppInfoController {
@PostMapping("/save")
public ResultDTO saveAppInfo(@RequestBody ModifyAppInfoRequest req) {
+ req.valid();
AppInfoDO appInfoDO;
Long id = req.getId();
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/OpenAPIController.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/OpenAPIController.java
index b9519f9c..b6bac2a4 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/OpenAPIController.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/OpenAPIController.java
@@ -94,6 +94,13 @@ public class OpenAPIController {
return ResultDTO.success(null);
}
+ @PostMapping(OpenAPIConstant.CANCEL_INSTANCE)
+ public ResultDTO cancelInstance(Long instanceId, Long appId) {
+ checkInstanceIdValid(instanceId, appId);
+ instanceService.cancelInstance(instanceId);
+ return ResultDTO.success(null);
+ }
+
@PostMapping(OpenAPIConstant.FETCH_INSTANCE_STATUS)
public ResultDTO fetchInstanceStatus(Long instanceId) {
InstanceStatus instanceStatus = instanceService.getInstanceStatus(instanceId);
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/ServerController.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/ServerController.java
index 768a6f71..d98cb025 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/ServerController.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/ServerController.java
@@ -1,5 +1,8 @@
package com.github.kfcfans.powerjob.server.web.controller;
+import com.alibaba.fastjson.JSONObject;
+import com.github.kfcfans.powerjob.common.utils.CommonUtils;
+import com.github.kfcfans.powerjob.common.utils.NetUtils;
import com.github.kfcfans.powerjob.server.akka.OhMyServer;
import com.github.kfcfans.powerjob.server.persistence.core.model.AppInfoDO;
import com.github.kfcfans.powerjob.server.persistence.core.repository.AppInfoRepository;
@@ -11,6 +14,7 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Optional;
+import java.util.TimeZone;
/**
* 处理Worker请求的 Controller
@@ -47,8 +51,13 @@ public class ServerController {
}
@GetMapping("/hello")
- public ResultDTO ping() {
- return ResultDTO.success("this is powerjob-server~");
+ public ResultDTO ping() {
+ JSONObject res = new JSONObject();
+ res.put("localHost", NetUtils.getLocalHost());
+ res.put("actorSystemAddress", OhMyServer.getActorSystemAddress());
+ res.put("serverTime", CommonUtils.formatTime(System.currentTimeMillis()));
+ res.put("serverTimeZone", TimeZone.getDefault().getDisplayName());
+ return ResultDTO.success(res);
}
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/request/ModifyAppInfoRequest.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/request/ModifyAppInfoRequest.java
index aeacc5db..77ea5da3 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/request/ModifyAppInfoRequest.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/request/ModifyAppInfoRequest.java
@@ -1,6 +1,9 @@
package com.github.kfcfans.powerjob.server.web.request;
+import com.github.kfcfans.powerjob.common.OmsException;
+import com.github.kfcfans.powerjob.common.utils.CommonUtils;
import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
/**
* 修改应用信息请求
@@ -14,4 +17,11 @@ public class ModifyAppInfoRequest {
private Long id;
private String appName;
private String password;
+
+ public void valid() {
+ CommonUtils.requireNonNull(appName, "appName can't be empty");
+ if (StringUtils.containsWhitespace(appName)) {
+ throw new OmsException("appName can't contains white space!");
+ }
+ }
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/response/InstanceDetailVO.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/response/InstanceDetailVO.java
index ad61500c..30c75864 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/response/InstanceDetailVO.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/response/InstanceDetailVO.java
@@ -22,6 +22,8 @@ import java.util.List;
@NoArgsConstructor
public class InstanceDetailVO {
+ // 任务预计执行时间
+ private String expectedTriggerTime;
// 任务整体开始时间
private String actualTriggerTime;
// 任务整体结束时间(可能不存在)
@@ -68,6 +70,7 @@ public class InstanceDetailVO {
// 格式化时间
vo.setFinishedTime(CommonUtils.formatTime(origin.getFinishedTime()));
vo.setActualTriggerTime(CommonUtils.formatTime(origin.getActualTriggerTime()));
+ vo.setExpectedTriggerTime(CommonUtils.formatTime(origin.getExpectedTriggerTime()));
// 拷贝 TaskDetail
if (origin.getTaskDetail() != null) {
diff --git a/powerjob-server/src/main/resources/application-daily.properties b/powerjob-server/src/main/resources/application-daily.properties
index 5d3a6146..cb7778b6 100644
--- a/powerjob-server/src/main/resources/application-daily.properties
+++ b/powerjob-server/src/main/resources/application-daily.properties
@@ -1,7 +1,7 @@
oms.env=DAILY
logging.config=classpath:logback-dev.xml
-####### 数据库配置 #######
+####### 外部数据库配置(需要用户更改为自己的数据库配置) #######
spring.datasource.core.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.core.jdbc-url=jdbc:mysql://localhost:3306/powerjob-daily?useUnicode=true&characterEncoding=UTF-8
spring.datasource.core.username=root
@@ -10,7 +10,7 @@ spring.datasource.core.hikari.maximum-pool-size=20
spring.datasource.core.hikari.minimum-idle=5
####### mongoDB配置,非核心依赖,可移除 #######
-spring.data.mongodb.uri=mongodb://remotehost:27017/powerjob-daily
+spring.data.mongodb.uri=mongodb://localhost:27017/powerjob-daily
####### 邮件配置(启用邮件报警则需要) #######
spring.mail.host=smtp.163.com
diff --git a/powerjob-server/src/main/resources/application.properties b/powerjob-server/src/main/resources/application.properties
index 1078fa1d..6dc9fd8b 100644
--- a/powerjob-server/src/main/resources/application.properties
+++ b/powerjob-server/src/main/resources/application.properties
@@ -2,8 +2,10 @@
server.port=7700
spring.profiles.active=daily
+spring.main.banner-mode=log
spring.jpa.open-in-view=false
spring.data.mongodb.repositories.type=none
+logging.level.org.mongodb=warn
# 文件上传配置
spring.servlet.multipart.enabled=true
diff --git a/powerjob-server/src/main/resources/static/js/1.js b/powerjob-server/src/main/resources/static/js/1.js
index eb98814f..e22d2fbb 100644
--- a/powerjob-server/src/main/resources/static/js/1.js
+++ b/powerjob-server/src/main/resources/static/js/1.js
@@ -8,7 +8,7 @@
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"InstanceDetail\",\n // 数据传递\n props: [\"instanceId\"],\n data: function data() {\n return {\n instanceDetail: {}\n };\n },\n methods: {\n fetchInstanceDetail: function fetchInstanceDetail() {\n var that = this;\n var url = \"/instance/detail?instanceId=\" + this.instanceId;\n this.axios.get(url).then(function (res) {\n return that.instanceDetail = res;\n });\n }\n },\n mounted: function mounted() {\n console.log(\"using InstanceId: \" + this.instanceId);\n this.fetchInstanceDetail();\n }\n});\n\n//# sourceURL=webpack:///./src/components/common/InstanceDetail.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
+eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"InstanceDetail\",\n // 数据传递\n props: [\"instanceId\"],\n data: function data() {\n return {\n instanceDetail: {}\n };\n },\n methods: {\n fetchInstanceDetail: function fetchInstanceDetail() {\n var that = this;\n var url = \"/instance/detail?instanceId=\" + this.instanceId;\n this.axios.get(url).then(function (res) {\n return that.instanceDetail = res;\n });\n }\n },\n mounted: function mounted() {\n console.log(\"using InstanceId: \" + this.instanceId);\n this.fetchInstanceDetail();\n }\n});\n\n//# sourceURL=webpack:///./src/components/common/InstanceDetail.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
@@ -20,7 +20,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n//\n/
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n [\n _c(\n \"el-row\",\n [\n _c(\n \"el-col\",\n { attrs: { offset: 20 } },\n [\n _c(\n \"el-button\",\n {\n attrs: { type: \"primary\" },\n on: { click: _vm.fetchInstanceDetail }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.refresh\")))]\n )\n ],\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\"el-col\", { attrs: { span: 24 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.instanceId\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(_vm._s(_vm.instanceId))\n ])\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n { staticStyle: { \"margin-top\": \"-20px\" } },\n [\n _c(\"el-col\", { attrs: { span: 8 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.status\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(\n _vm._s(\n this.common.translateInstanceStatus(_vm.instanceDetail.status)\n )\n )\n ])\n ]),\n _c(\"el-col\", { attrs: { span: 16 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.runningTimes\")) + \":\"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(_vm._s(_vm.instanceDetail.runningTimes))\n ])\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\"el-col\", { attrs: { span: 24 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.taskTrackerAddress\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(\" \" + _vm._s(_vm.instanceDetail.taskTrackerAddress))\n ])\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\"el-col\", { attrs: { span: 8 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.startTime\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(\" \" + _vm._s(_vm.instanceDetail.actualTriggerTime))\n ])\n ]),\n _c(\"el-col\", { attrs: { span: 8 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.finishedTime\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(_vm._s(_vm.instanceDetail.finishedTime))\n ])\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\"el-col\", { attrs: { span: 24 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.result\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(\" \" + _vm._s(_vm.instanceDetail.result))\n ])\n ])\n ],\n 1\n ),\n _c(\"el-row\", { attrs: { id: \"taskDetail\" } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.subTaskInfo\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(_vm._s(_vm.instanceDetail.taskDetail))\n ])\n ]),\n _c(\n \"el-row\",\n [\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(_vm._s(_vm.$t(\"message.secondlyJobHistory\")) + \":\")\n ]),\n _c(\n \"el-table\",\n {\n staticStyle: { width: \"100%\" },\n attrs: { data: _vm.instanceDetail.subInstanceDetails }\n },\n [\n _c(\"el-table-column\", {\n attrs: {\n prop: \"subInstanceId\",\n label: _vm.$t(\"message.subInstanceId\"),\n width: \"120\"\n }\n }),\n _c(\"el-table-column\", {\n attrs: {\n prop: \"startTime\",\n label: _vm.$t(\"message.startTime\"),\n width: \"160\"\n }\n }),\n _c(\"el-table-column\", {\n attrs: {\n prop: \"finishedTime\",\n label: _vm.$t(\"message.finishedTime\"),\n width: \"160\"\n }\n }),\n _c(\"el-table-column\", {\n attrs: { label: _vm.$t(\"message.status\"), width: \"160\" },\n scopedSlots: _vm._u([\n {\n key: \"default\",\n fn: function(scope) {\n return [\n _vm._v(\n \" \" +\n _vm._s(\n _vm.common.translateInstanceStatus(\n scope.row.status\n )\n ) +\n \" \"\n )\n ]\n }\n }\n ])\n }),\n _c(\"el-table-column\", {\n attrs: { prop: \"result\", label: _vm.$t(\"message.result\") }\n })\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/common/InstanceDetail.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%2241f1f4da-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n [\n _c(\n \"el-row\",\n [\n _c(\n \"el-col\",\n { attrs: { offset: 20 } },\n [\n _c(\n \"el-button\",\n {\n attrs: { type: \"primary\" },\n on: { click: _vm.fetchInstanceDetail }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.refresh\")))]\n )\n ],\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\"el-col\", { attrs: { span: 24 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.instanceId\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(_vm._s(_vm.instanceId))\n ])\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n { staticStyle: { \"margin-top\": \"-20px\" } },\n [\n _c(\"el-col\", { attrs: { span: 8 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.status\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(\n _vm._s(\n this.common.translateInstanceStatus(_vm.instanceDetail.status)\n )\n )\n ])\n ]),\n _c(\"el-col\", { attrs: { span: 16 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.runningTimes\")) + \":\"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(_vm._s(_vm.instanceDetail.runningTimes))\n ])\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\"el-col\", { attrs: { span: 24 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.taskTrackerAddress\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(\" \" + _vm._s(_vm.instanceDetail.taskTrackerAddress))\n ])\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\"el-col\", { attrs: { span: 24 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.expectedTriggerTime\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(\" \" + _vm._s(_vm.instanceDetail.expectedTriggerTime))\n ])\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\"el-col\", { attrs: { span: 8 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.startTime\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(\" \" + _vm._s(_vm.instanceDetail.actualTriggerTime))\n ])\n ]),\n _c(\"el-col\", { attrs: { span: 8 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.finishedTime\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(_vm._s(_vm.instanceDetail.finishedTime))\n ])\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\"el-col\", { attrs: { span: 24 } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.result\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(\" \" + _vm._s(_vm.instanceDetail.result))\n ])\n ])\n ],\n 1\n ),\n _c(\"el-row\", { attrs: { id: \"taskDetail\" } }, [\n _vm._v(\" \" + _vm._s(_vm.$t(\"message.subTaskInfo\")) + \": \"),\n _c(\"span\", { staticClass: \"title\" }, [\n _vm._v(_vm._s(_vm.instanceDetail.taskDetail))\n ])\n ]),\n _c(\"el-divider\", { attrs: { \"content-position\": \"center\" } }, [\n _vm._v(_vm._s(_vm.$t(\"message.secondlyJobHistory\")) + \":\")\n ]),\n _c(\n \"el-row\",\n [\n _c(\n \"el-table\",\n {\n staticStyle: { width: \"100%\" },\n attrs: { data: _vm.instanceDetail.subInstanceDetails }\n },\n [\n _c(\"el-table-column\", {\n attrs: {\n prop: \"subInstanceId\",\n label: _vm.$t(\"message.subInstanceId\"),\n width: \"120\"\n }\n }),\n _c(\"el-table-column\", {\n attrs: {\n prop: \"startTime\",\n label: _vm.$t(\"message.startTime\"),\n width: \"160\"\n }\n }),\n _c(\"el-table-column\", {\n attrs: {\n prop: \"finishedTime\",\n label: _vm.$t(\"message.finishedTime\"),\n width: \"160\"\n }\n }),\n _c(\"el-table-column\", {\n attrs: { label: _vm.$t(\"message.status\"), width: \"160\" },\n scopedSlots: _vm._u([\n {\n key: \"default\",\n fn: function(scope) {\n return [\n _vm._v(\n \" \" +\n _vm._s(\n _vm.common.translateInstanceStatus(\n scope.row.status\n )\n ) +\n \" \"\n )\n ]\n }\n }\n ])\n }),\n _c(\"el-table-column\", {\n attrs: { prop: \"result\", label: _vm.$t(\"message.result\") }\n })\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/common/InstanceDetail.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%2241f1f4da-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
diff --git a/powerjob-server/src/main/resources/static/js/8.js b/powerjob-server/src/main/resources/static/js/8.js
index df064cd2..5fa20e94 100644
--- a/powerjob-server/src/main/resources/static/js/8.js
+++ b/powerjob-server/src/main/resources/static/js/8.js
@@ -8,7 +8,7 @@
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _common_InstanceDetail__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/InstanceDetail */ \"./src/components/common/InstanceDetail.vue\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"InstanceManager\",\n components: {\n InstanceDetail: _common_InstanceDetail__WEBPACK_IMPORTED_MODULE_0__[\"default\"]\n },\n data: function data() {\n return {\n // 实例查询对象\n instanceQueryContent: {\n appId: this.$store.state.appInfo.id,\n index: 0,\n pageSize: 10,\n instanceId: undefined,\n wfInstanceId: undefined,\n status: \"\",\n jobId: undefined,\n type: \"NORMAL\"\n },\n // 实例查询结果\n instancePageResult: {\n pageSize: 10,\n totalItems: 0,\n data: []\n },\n // 详细信息弹出框是否可见\n instanceDetailVisible: false,\n // 日志查询对象\n logQueryContent: {\n instanceId: undefined,\n index: 0\n },\n // 日志对象\n paginableInstanceLog: {\n index: 0,\n totalPages: 0,\n data: \"\"\n },\n // 日志弹出框是否可见\n instanceLogVisible: false,\n currentInstanceId: undefined,\n // 任务实例状态选择\n instanceStatusOptions: [{\n key: \"\",\n label: this.$t('message.all')\n }, {\n key: \"WAITING_DISPATCH\",\n label: this.$t('message.waitingDispatch')\n }, {\n key: \"WAITING_WORKER_RECEIVE\",\n label: this.$t('message.waitingWorkerReceive')\n }, {\n key: \"RUNNING\",\n label: this.$t('message.running')\n }, {\n key: \"FAILED\",\n label: this.$t('message.failed')\n }, {\n key: \"SUCCEED\",\n label: this.$t('message.success')\n }, {\n key: \"STOPPED\",\n label: this.$t('message.stopped')\n }]\n };\n },\n methods: {\n // 查询任务实例信息\n listInstanceInfos: function listInstanceInfos() {\n var that = this;\n that.axios.post(\"/instance/list\", that.instanceQueryContent).then(function (res) {\n that.instancePageResult = res;\n });\n },\n // 点击重置按钮\n onClickRest: function onClickRest() {\n this.instanceQueryContent.jobId = undefined;\n this.instanceQueryContent.instanceId = undefined;\n this.instanceQueryContent.wfInstanceId = undefined;\n this.instanceQueryContent.status = \"\";\n this.listInstanceInfos();\n },\n // 点击查询详情\n onClickShowDetail: function onClickShowDetail(data) {\n this.instanceDetailVisible = true;\n this.currentInstanceId = data.instanceId;\n },\n // 点击停止实例\n onClickStop: function onClickStop(data) {\n var _this = this;\n\n var that = this;\n var url = \"/instance/stop?instanceId=\" + data.instanceId;\n this.axios.get(url).then(function () {\n that.$message.success(_this.$t('message.success')); // 重新加载列表\n\n that.listInstanceInfos();\n });\n },\n // 换页\n onClickChangeInstancePage: function onClickChangeInstancePage(index) {\n // 后端从0开始,前端从1开始\n this.instanceQueryContent.index = index - 1;\n this.listInstanceInfos();\n },\n instanceTableRowClassName: function instanceTableRowClassName(_ref) {\n var row = _ref.row;\n\n switch (row.status) {\n // 失败\n case 4:\n return 'error-row';\n // 成功\n\n case 5:\n return 'success-row';\n\n case 10:\n return 'warning-row';\n }\n },\n // 查看日志\n queryLog: function queryLog() {\n var that = this;\n var url = \"/instance/log?instanceId=\" + this.logQueryContent.instanceId + \"&index=\" + this.logQueryContent.index;\n this.axios.get(url).then(function (res) {\n that.paginableInstanceLog = res;\n that.instanceLogVisible = true;\n });\n },\n // 查看在线日志\n onClickShowLog: function onClickShowLog(data) {\n this.logQueryContent.instanceId = data.instanceId;\n this.logQueryContent.index = 0;\n this.queryLog();\n },\n // 查看其它页的在线日志\n onClickChangeLogPage: function onClickChangeLogPage(index) {\n this.logQueryContent.index = index - 1;\n this.queryLog();\n },\n // 下载日志\n onclickDownloadLog: function onclickDownloadLog() {\n var url = \"/instance/downloadLogUrl?instanceId=\" + this.logQueryContent.instanceId;\n this.axios.get(url).then(function (res) {\n return window.open(res);\n });\n },\n // 获取状态\n fetchStatus: function fetchStatus(s) {\n return this.common.translateInstanceStatus(s);\n }\n },\n mounted: function mounted() {\n this.listInstanceInfos();\n }\n});\n\n//# sourceURL=webpack:///./src/components/views/InstanceManager.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _common_InstanceDetail__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/InstanceDetail */ \"./src/components/common/InstanceDetail.vue\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"InstanceManager\",\n components: {\n InstanceDetail: _common_InstanceDetail__WEBPACK_IMPORTED_MODULE_0__[\"default\"]\n },\n data: function data() {\n return {\n // 实例查询对象\n instanceQueryContent: {\n appId: this.$store.state.appInfo.id,\n index: 0,\n pageSize: 10,\n instanceId: undefined,\n wfInstanceId: undefined,\n status: \"\",\n jobId: undefined,\n type: \"NORMAL\"\n },\n // 实例查询结果\n instancePageResult: {\n pageSize: 10,\n totalItems: 0,\n data: []\n },\n // 详细信息弹出框是否可见\n instanceDetailVisible: false,\n // 日志查询对象\n logQueryContent: {\n instanceId: undefined,\n index: 0\n },\n // 日志对象\n paginableInstanceLog: {\n index: 0,\n totalPages: 0,\n data: \"\"\n },\n // 日志弹出框是否可见\n instanceLogVisible: false,\n currentInstanceId: undefined,\n // 任务实例状态选择\n instanceStatusOptions: [{\n key: \"\",\n label: this.$t('message.all')\n }, {\n key: \"WAITING_DISPATCH\",\n label: this.$t('message.waitingDispatch')\n }, {\n key: \"WAITING_WORKER_RECEIVE\",\n label: this.$t('message.waitingWorkerReceive')\n }, {\n key: \"RUNNING\",\n label: this.$t('message.running')\n }, {\n key: \"FAILED\",\n label: this.$t('message.failed')\n }, {\n key: \"SUCCEED\",\n label: this.$t('message.success')\n }, {\n key: \"CANCELED\",\n label: this.$t('message.canceled')\n }, {\n key: \"STOPPED\",\n label: this.$t('message.stopped')\n }]\n };\n },\n methods: {\n // 查询任务实例信息\n listInstanceInfos: function listInstanceInfos() {\n var that = this;\n that.axios.post(\"/instance/list\", that.instanceQueryContent).then(function (res) {\n that.instancePageResult = res;\n });\n },\n // 点击重置按钮\n onClickRest: function onClickRest() {\n this.instanceQueryContent.jobId = undefined;\n this.instanceQueryContent.instanceId = undefined;\n this.instanceQueryContent.wfInstanceId = undefined;\n this.instanceQueryContent.status = \"\";\n this.listInstanceInfos();\n },\n // 点击查询详情\n onClickShowDetail: function onClickShowDetail(data) {\n this.instanceDetailVisible = true;\n this.currentInstanceId = data.instanceId;\n },\n // 点击停止实例\n onClickStop: function onClickStop(data) {\n var _this = this;\n\n var that = this;\n var url = \"/instance/stop?instanceId=\" + data.instanceId;\n this.axios.get(url).then(function () {\n that.$message.success(_this.$t('message.success')); // 重新加载列表\n\n that.listInstanceInfos();\n });\n },\n // 换页\n onClickChangeInstancePage: function onClickChangeInstancePage(index) {\n // 后端从0开始,前端从1开始\n this.instanceQueryContent.index = index - 1;\n this.listInstanceInfos();\n },\n instanceTableRowClassName: function instanceTableRowClassName(_ref) {\n var row = _ref.row;\n\n switch (row.status) {\n // 失败\n case 4:\n return 'error-row';\n // 成功\n\n case 5:\n return 'success-row';\n\n case 9:\n case 10:\n return 'warning-row';\n }\n },\n // 查看日志\n queryLog: function queryLog() {\n var that = this;\n var url = \"/instance/log?instanceId=\" + this.logQueryContent.instanceId + \"&index=\" + this.logQueryContent.index;\n this.axios.get(url).then(function (res) {\n that.paginableInstanceLog = res;\n that.instanceLogVisible = true;\n });\n },\n // 查看在线日志\n onClickShowLog: function onClickShowLog(data) {\n this.logQueryContent.instanceId = data.instanceId;\n this.logQueryContent.index = 0;\n this.queryLog();\n },\n // 查看其它页的在线日志\n onClickChangeLogPage: function onClickChangeLogPage(index) {\n this.logQueryContent.index = index - 1;\n this.queryLog();\n },\n // 下载日志\n onclickDownloadLog: function onclickDownloadLog() {\n var url = \"/instance/downloadLogUrl?instanceId=\" + this.logQueryContent.instanceId;\n this.axios.get(url).then(function (res) {\n return window.open(res);\n });\n },\n // 获取状态\n fetchStatus: function fetchStatus(s) {\n return this.common.translateInstanceStatus(s);\n }\n },\n mounted: function mounted() {\n this.listInstanceInfos();\n }\n});\n\n//# sourceURL=webpack:///./src/components/views/InstanceManager.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
diff --git a/powerjob-server/src/main/resources/static/js/app.js b/powerjob-server/src/main/resources/static/js/app.js
index 51bad83a..7311d908 100644
--- a/powerjob-server/src/main/resources/static/js/app.js
+++ b/powerjob-server/src/main/resources/static/js/app.js
@@ -497,7 +497,7 @@ eval("module.exports = __webpack_require__.p + \"img/powerjob-console-logo.ac01c
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./i18n/i18n */ \"./src/i18n/i18n.js\");\n\n\nvar timestamp2Str = function timestamp2Str(ts) {\n if (ts < 10000) {\n return \"N/A\";\n }\n\n try {\n if (ts) {\n var time = new Date(ts);\n var y = time.getFullYear();\n var M = time.getMonth() + 1;\n var d = time.getDate();\n var h = time.getHours();\n var m = time.getMinutes();\n var s = time.getSeconds();\n return y + '-' + addZero(M) + '-' + addZero(d) + ' ' + addZero(h) + ':' + addZero(m) + ':' + addZero(s);\n } else {\n return '';\n }\n } catch (e) {\n return \"N/A\";\n }\n}; // 公共函数,涉及到 i18n ,放进 common.js 报错,暂时先放在这里吧\n\n\nvar translateInstanceStatus = function translateInstanceStatus(status) {\n switch (status) {\n case 1:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.waitingDispatch');\n\n case 2:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.waitingWorkerReceive');\n\n case 3:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.running');\n\n case 4:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.failed');\n\n case 5:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.success');\n\n case 10:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.stopped');\n\n default:\n return \"unknown\";\n }\n};\n\nvar translateWfInstanceStatus = function translateWfInstanceStatus(status) {\n switch (status) {\n case 1:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.wfWaiting');\n\n case 2:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.running');\n\n case 3:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.failed');\n\n case 4:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.success');\n\n case 10:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.stopped');\n\n default:\n return \"unknown\";\n }\n}; // 更换语言\n\n\nvar switchLanguage = function switchLanguage(cmd) {\n console.log(\"switch language to %o\", cmd);\n _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].locale = cmd; // 存储到LangStorage\n\n window.localStorage.setItem('oms_lang', cmd);\n};\n\nfunction addZero(m) {\n return m < 10 ? '0' + m : m;\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n timestamp2Str: timestamp2Str,\n translateInstanceStatus: translateInstanceStatus,\n translateWfInstanceStatus: translateWfInstanceStatus,\n switchLanguage: switchLanguage\n});\n\n//# sourceURL=webpack:///./src/common.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./i18n/i18n */ \"./src/i18n/i18n.js\");\n\n\nvar timestamp2Str = function timestamp2Str(ts) {\n if (ts < 10000) {\n return \"N/A\";\n }\n\n try {\n if (ts) {\n var time = new Date(ts);\n var y = time.getFullYear();\n var M = time.getMonth() + 1;\n var d = time.getDate();\n var h = time.getHours();\n var m = time.getMinutes();\n var s = time.getSeconds();\n return y + '-' + addZero(M) + '-' + addZero(d) + ' ' + addZero(h) + ':' + addZero(m) + ':' + addZero(s);\n } else {\n return '';\n }\n } catch (e) {\n return \"N/A\";\n }\n}; // 公共函数,涉及到 i18n ,放进 common.js 报错,暂时先放在这里吧\n\n\nvar translateInstanceStatus = function translateInstanceStatus(status) {\n switch (status) {\n case 1:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.waitingDispatch');\n\n case 2:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.waitingWorkerReceive');\n\n case 3:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.running');\n\n case 4:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.failed');\n\n case 5:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.success');\n\n case 9:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.canceled');\n\n case 10:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.stopped');\n\n default:\n return \"unknown\";\n }\n};\n\nvar translateWfInstanceStatus = function translateWfInstanceStatus(status) {\n switch (status) {\n case 1:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.wfWaiting');\n\n case 2:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.running');\n\n case 3:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.failed');\n\n case 4:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.success');\n\n case 10:\n return _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].t('message.stopped');\n\n default:\n return \"unknown\";\n }\n}; // 更换语言\n\n\nvar switchLanguage = function switchLanguage(cmd) {\n console.log(\"switch language to %o\", cmd);\n _i18n_i18n__WEBPACK_IMPORTED_MODULE_0__[\"default\"].locale = cmd; // 存储到LangStorage\n\n window.localStorage.setItem('oms_lang', cmd);\n};\n\nfunction addZero(m) {\n return m < 10 ? '0' + m : m;\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n timestamp2Str: timestamp2Str,\n translateInstanceStatus: translateInstanceStatus,\n translateWfInstanceStatus: translateWfInstanceStatus,\n switchLanguage: switchLanguage\n});\n\n//# sourceURL=webpack:///./src/common.js?");
/***/ }),
@@ -676,7 +676,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue_
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/esm/objectSpread2.js\");\n/* harmony import */ var element_ui_lib_locale_lang_zh_CN__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! element-ui/lib/locale/lang/zh-CN */ \"./node_modules/element-ui/lib/locale/lang/zh-CN.js\");\n/* harmony import */ var element_ui_lib_locale_lang_zh_CN__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(element_ui_lib_locale_lang_zh_CN__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\nvar cn = Object(_Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({\n message: {\n // common\n 'save': '保存',\n 'cancel': '取消',\n 'refresh': '刷新',\n 'query': '查询',\n 'reset': '重置',\n 'keyword': '关键字',\n 'run': '运行',\n 'edit': '编辑',\n 'delete': '删除',\n 'success': '成功',\n 'failed': '失败',\n 'detail': '详情',\n 'download': '下载',\n 'stop': '停止',\n 'back': '返回',\n 'all': '全部',\n // 欢迎界面\n 'appRegister': '执行应用注册',\n 'userRegister': '报警用户录入',\n 'appNameInputPLH': '请输入应用名称',\n 'appName': '应用名称',\n 'appPassword': '密码',\n 'register': '注册',\n 'name': '姓名',\n 'phone': '手机号',\n 'email': '邮箱地址',\n 'welcomeTitle': '欢迎使用 PowerJob!',\n 'login': '登陆',\n 'logout': '退出',\n 'changeAppInfo': '修改应用信息',\n 'newPassword': '新密码',\n 'newPassword2': '确认密码',\n 'stayLogged': '保持登录状态',\n // 左侧tab栏\n 'tabHome': '系统首页',\n 'tabJobManage': '任务管理',\n 'tabJobInstance': '任务实例',\n 'tabWorkflowManage': '工作流管理',\n 'tabWfInstance': '工作流实例',\n 'tabContainerOps': '容器',\n 'tabTemplate': '模版生成',\n 'tabContainerManager': '容器运维',\n // 系统首页\n 'omsServerTime': '调度服务器时间',\n 'omsServerTimezone': '调度服务器时区',\n 'localBrowserTime': '本地时间',\n 'localBrowserTimezone': '本地时区',\n 'githubURL': '项目地址',\n 'docURL': '文档地址',\n 'totalJobNum': '任务总数',\n 'runningInstanceNum': '当前运行实例数',\n 'recentFailedInstanceNum': '近期失败任务数',\n 'workerNum': '集群机器数',\n 'workerAddress': '机器地址',\n 'cpuLoad': 'CPU 占用',\n 'memoryLoad': '内存占用',\n 'diskLoad': '磁盘占用',\n // 任务管理\n 'jobId': '任务ID',\n 'instanceId': '任务实例ID',\n 'jobName': '任务名称',\n 'scheduleInfo': '定时信息',\n 'executeType': '执行类型',\n 'processorType': '处理器类型',\n 'status': '状态',\n 'operation': '操作',\n 'newJob': '新建任务',\n 'jobDescription': '任务描述',\n 'jobParams': '任务参数',\n 'timeExpressionType': '时间表达式类型',\n 'timeExpressionPlaceHolder': 'CRON填写CRON表达式,秒级任务填写整数,API无需填写',\n 'executeConfig': '执行配置',\n 'javaProcessorInfoPLH': '全限定类名,eg:com.github.kfcfans.DemoProcessor',\n 'containerProcessorInfoPLH': '容器ID#全限定类名,eg:1#com.github.kfcfans.DemoProcessor',\n 'shellProcessorInfoPLH': 'SHELL脚本文件内容',\n 'pythonProcessorInfoPLH': 'Python脚本文件内容',\n 'runtimeConfig': '运行时配置',\n 'maxInstanceNum': '最大实例数',\n 'threadConcurrency': '单机线程并发度',\n 'timeout': '运行时间限制(毫秒)',\n 'retryConfig': '重试配置',\n 'taskRetryTimes': 'Instance重试次数',\n 'subTaskRetryTimes': \"Task重试次数\",\n 'workerConfig': '机器配置',\n 'minCPU': '最低CPU核心数',\n 'minMemory': '最低内存(GB)',\n 'minDisk': '最低磁盘空间(GB)',\n 'clusterConfig': '集群配置',\n 'designatedWorkerAddress': '执行机器地址',\n 'designatedWorkerAddressPLH': '执行机器地址(可选,不指定代表全部;多值英文逗号分割)',\n 'maxWorkerNum': '最大执行机器数量',\n 'maxWorkerNumPLH': '最大执行机器数量(0代表不限)',\n 'alarmConfig': '报警配置',\n 'alarmSelectorPLH': '选择报警通知人员',\n 'standalone': '单机执行',\n 'broadcast': '广播执行',\n 'map': 'Map执行',\n 'mapReduce': 'MapReduce执行',\n 'fixRate': '固定频率(毫秒)',\n 'fixDelay': '固定延迟(毫秒)',\n 'workflow': '工作流',\n 'onlineCronTool': '在线生成工具',\n 'javaContainer': 'Java(容器)',\n // 任务实例管理\n 'wfInstanceId': '工作流实例ID',\n 'normalInstance': '普通任务实例',\n 'wfInstance': '工作流任务实例',\n 'triggerTime': '触发时间',\n 'finishedTime': '结束时间',\n 'log': '日志',\n 'runningTimes': '运行次数',\n 'taskTrackerAddress': 'TaskTracker 地址',\n 'startTime': '开始时间',\n 'result': '运行结果',\n 'subTaskInfo': '子任务数据',\n 'secondlyJobHistory': '最近10条秒级任务历史记录',\n 'subInstanceId': '子任务实例ID',\n // 工作流管理\n 'wfId': '工作流ID',\n 'wfName': '工作流名称',\n 'newWorkflow': '新建工作流',\n 'wfDescription': '工作流描述',\n 'importJob': '导入任务',\n 'deleteJob': '删除任务',\n 'newStartPoint': '新增起点',\n 'newEndPoint': '新增终点',\n 'deleteEdge': '删除边',\n 'importJobTitle': \"请选择需要导入工作流的任务\",\n 'wfTimeExpressionPLH': 'CRON填写CRON表达式,API无需填写',\n 'import': '导入',\n 'ntfClickNeedDeleteNode': '请点击需要删除的节点',\n 'ntfClickStartPoint': '请点击起始节点',\n 'ntfClickTargetPoint': '请点击目标节点',\n 'ntfClickDeleteEdge': '请点击需要删除的边',\n 'ntfAddStartPointFirst': '请先添加起点!',\n 'ntfInvalidEdge': '非法操作(起点终点相同)!',\n // 工作流实例\n 'wfTips': 'tips:点击节点可查看任务实例详情',\n 'ntfClickWaitingNode': '等待上游任务中...未生成任务实例,无法查看详情!',\n // 容器\n 'newContainer': '新增容器',\n 'containerType': '容器类型',\n 'containerGitURL': 'Git仓库地址',\n 'branchName': '分支名称',\n 'username': '用户名',\n 'password': '密码',\n 'containerId': '容器ID',\n 'containerName': '容器名称',\n 'containerVersion': '容器版本',\n 'deployTime': '部署时间',\n 'deploy': '部署',\n 'deployedWorkerList': '机器列表',\n 'uploadTips': '拖拽或点击文件后会自动上传',\n // 任务实例状态\n 'waitingDispatch': '等待派发',\n 'waitingWorkerReceive': '等待Worker接收',\n 'running': '运行中',\n 'stopped': '手动停止',\n 'wfWaiting': '等待调度',\n 'waitingUpstream': '等待上游节点'\n }\n}, element_ui_lib_locale_lang_zh_CN__WEBPACK_IMPORTED_MODULE_1___default.a);\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (cn);\n\n//# sourceURL=webpack:///./src/i18n/langs/cn.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Users_zb_Documents_own_PowerJob_Console_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/esm/objectSpread2.js\");\n/* harmony import */ var element_ui_lib_locale_lang_zh_CN__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! element-ui/lib/locale/lang/zh-CN */ \"./node_modules/element-ui/lib/locale/lang/zh-CN.js\");\n/* harmony import */ var element_ui_lib_locale_lang_zh_CN__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(element_ui_lib_locale_lang_zh_CN__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\nvar cn = Object(_Users_zb_Documents_own_PowerJob_Console_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({\n message: {\n // common\n 'save': '保存',\n 'cancel': '取消',\n 'refresh': '刷新',\n 'query': '查询',\n 'reset': '重置',\n 'keyword': '关键字',\n 'run': '运行',\n 'edit': '编辑',\n 'delete': '删除',\n 'success': '成功',\n 'failed': '失败',\n 'detail': '详情',\n 'download': '下载',\n 'stop': '停止',\n 'back': '返回',\n 'all': '全部',\n // 欢迎界面\n 'appRegister': '执行应用注册',\n 'userRegister': '报警用户录入',\n 'appNameInputPLH': '请输入应用名称',\n 'appName': '应用名称',\n 'appPassword': '密码',\n 'register': '注册',\n 'name': '姓名',\n 'phone': '手机号',\n 'email': '邮箱地址',\n 'welcomeTitle': '欢迎使用 PowerJob!',\n 'login': '登陆',\n 'logout': '退出',\n 'changeAppInfo': '修改应用信息',\n 'newPassword': '新密码',\n 'newPassword2': '确认密码',\n 'stayLogged': '保持登录状态',\n // 左侧tab栏\n 'tabHome': '系统首页',\n 'tabJobManage': '任务管理',\n 'tabJobInstance': '任务实例',\n 'tabWorkflowManage': '工作流管理',\n 'tabWfInstance': '工作流实例',\n 'tabContainerOps': '容器',\n 'tabTemplate': '模版生成',\n 'tabContainerManager': '容器运维',\n // 系统首页\n 'omsServerTime': '调度服务器时间',\n 'omsServerTimezone': '调度服务器时区',\n 'localBrowserTime': '本地时间',\n 'localBrowserTimezone': '本地时区',\n 'githubURL': '项目地址',\n 'docURL': '文档地址',\n 'totalJobNum': '任务总数',\n 'runningInstanceNum': '当前运行实例数',\n 'recentFailedInstanceNum': '近期失败任务数',\n 'workerNum': '集群机器数',\n 'workerAddress': '机器地址',\n 'cpuLoad': 'CPU 占用',\n 'memoryLoad': '内存占用',\n 'diskLoad': '磁盘占用',\n // 任务管理\n 'jobId': '任务ID',\n 'instanceId': '任务实例ID',\n 'jobName': '任务名称',\n 'scheduleInfo': '定时信息',\n 'executeType': '执行类型',\n 'processorType': '处理器类型',\n 'status': '状态',\n 'operation': '操作',\n 'newJob': '新建任务',\n 'jobDescription': '任务描述',\n 'jobParams': '任务参数',\n 'timeExpressionType': '时间表达式类型',\n 'timeExpressionPlaceHolder': 'CRON填写CRON表达式,秒级任务填写整数,API无需填写',\n 'executeConfig': '执行配置',\n 'javaProcessorInfoPLH': '全限定类名,eg:com.github.kfcfans.DemoProcessor',\n 'containerProcessorInfoPLH': '容器ID#全限定类名,eg:1#com.github.kfcfans.DemoProcessor',\n 'shellProcessorInfoPLH': 'SHELL脚本文件内容',\n 'pythonProcessorInfoPLH': 'Python脚本文件内容',\n 'runtimeConfig': '运行时配置',\n 'maxInstanceNum': '最大实例数',\n 'threadConcurrency': '单机线程并发度',\n 'timeout': '运行时间限制(毫秒)',\n 'retryConfig': '重试配置',\n 'taskRetryTimes': 'Instance重试次数',\n 'subTaskRetryTimes': \"Task重试次数\",\n 'workerConfig': '机器配置',\n 'minCPU': '最低CPU核心数',\n 'minMemory': '最低内存(GB)',\n 'minDisk': '最低磁盘空间(GB)',\n 'clusterConfig': '集群配置',\n 'designatedWorkerAddress': '执行机器地址',\n 'designatedWorkerAddressPLH': '执行机器地址(可选,不指定代表全部;多值英文逗号分割)',\n 'maxWorkerNum': '最大执行机器数量',\n 'maxWorkerNumPLH': '最大执行机器数量(0代表不限)',\n 'alarmConfig': '报警配置',\n 'alarmSelectorPLH': '选择报警通知人员',\n 'standalone': '单机执行',\n 'broadcast': '广播执行',\n 'map': 'Map执行',\n 'mapReduce': 'MapReduce执行',\n 'fixRate': '固定频率(毫秒)',\n 'fixDelay': '固定延迟(毫秒)',\n 'workflow': '工作流',\n 'onlineCronTool': '在线生成工具',\n 'javaContainer': 'Java(容器)',\n // 任务实例管理\n 'wfInstanceId': '工作流实例ID',\n 'normalInstance': '普通任务实例',\n 'wfInstance': '工作流任务实例',\n 'triggerTime': '触发时间',\n 'finishedTime': '结束时间',\n 'log': '日志',\n 'runningTimes': '运行次数',\n 'taskTrackerAddress': 'TaskTracker 地址',\n 'startTime': '开始时间',\n 'expectedTriggerTime': '预计执行时间',\n 'result': '任务结果',\n 'subTaskInfo': 'Task 信息',\n 'secondlyJobHistory': '最近 10 条秒级任务历史记录(秒级任务专用)',\n 'subInstanceId': '子任务实例ID',\n // 工作流管理\n 'wfId': '工作流ID',\n 'wfName': '工作流名称',\n 'newWorkflow': '新建工作流',\n 'wfDescription': '工作流描述',\n 'importJob': '导入任务',\n 'deleteJob': '删除任务',\n 'newStartPoint': '新增起点',\n 'newEndPoint': '新增终点',\n 'deleteEdge': '删除边',\n 'importJobTitle': \"请选择需要导入工作流的任务\",\n 'wfTimeExpressionPLH': 'CRON填写CRON表达式,API无需填写',\n 'import': '导入',\n 'ntfClickNeedDeleteNode': '请点击需要删除的节点',\n 'ntfClickStartPoint': '请点击起始节点',\n 'ntfClickTargetPoint': '请点击目标节点',\n 'ntfClickDeleteEdge': '请点击需要删除的边',\n 'ntfAddStartPointFirst': '请先添加起点!',\n 'ntfInvalidEdge': '非法操作(起点终点相同)!',\n // 工作流实例\n 'wfTips': 'tips:点击节点可查看任务实例详情',\n 'ntfClickWaitingNode': '等待上游任务中...未生成任务实例,无法查看详情!',\n // 容器\n 'newContainer': '新增容器',\n 'containerType': '容器类型',\n 'containerGitURL': 'Git仓库地址',\n 'branchName': '分支名称',\n 'username': '用户名',\n 'password': '密码',\n 'containerId': '容器ID',\n 'containerName': '容器名称',\n 'containerVersion': '容器版本',\n 'deployTime': '部署时间',\n 'deploy': '部署',\n 'deployedWorkerList': '机器列表',\n 'uploadTips': '拖拽或点击文件后会自动上传',\n // 任务实例状态\n 'waitingDispatch': '等待派发',\n 'waitingWorkerReceive': '等待Worker接收',\n 'running': '运行中',\n 'stopped': '手动停止',\n 'canceled': '手动取消',\n 'wfWaiting': '等待调度',\n 'waitingUpstream': '等待上游节点'\n }\n}, element_ui_lib_locale_lang_zh_CN__WEBPACK_IMPORTED_MODULE_1___default.a);\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (cn);\n\n//# sourceURL=webpack:///./src/i18n/langs/cn.js?");
/***/ }),
@@ -688,7 +688,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Use
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/esm/objectSpread2.js\");\n/* harmony import */ var element_ui_lib_locale_lang_en__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! element-ui/lib/locale/lang/en */ \"./node_modules/element-ui/lib/locale/lang/en.js\");\n/* harmony import */ var element_ui_lib_locale_lang_en__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(element_ui_lib_locale_lang_en__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\nvar en = Object(_Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({\n message: {\n 'save': 'save',\n 'cancel': 'cancel',\n 'refresh': 'refresh',\n 'query': 'query',\n 'reset': 'reset',\n 'keyword': 'keyword',\n 'run': 'run',\n 'edit': 'edit',\n 'delete': 'delete',\n 'success': 'success',\n 'failed': 'failed',\n 'detail': 'detail',\n 'download': 'download',\n 'stop': 'stop',\n 'back': 'back',\n 'all': 'ALL',\n // 欢迎界面\n 'appRegister': 'App Registration',\n 'userRegister': 'User Registration',\n 'appNameInputPLH': 'Enter The AppName',\n 'appName': 'AppName',\n 'appPassword': 'AppPassword',\n 'register': 'register',\n 'name': 'name',\n 'phone': 'phone',\n 'email': 'email',\n 'welcomeTitle': 'Welcome to use PowerJob!',\n 'login': 'Login',\n 'logout': 'Logout',\n 'changeAppInfo': 'Change AppInfo',\n 'newPassword': 'New Password',\n 'newPassword2': 'Check New Password',\n 'stayLogged': 'Keep me logged in',\n 'tabHome': 'Home',\n 'tabJobManage': 'JobManage',\n 'tabJobInstance': 'JobInstance',\n 'tabWorkflowManage': 'WorkflowManage',\n 'tabWfInstance': 'WorkflowInstance',\n 'tabContainerOps': 'ContainerOps',\n 'tabTemplate': 'TemplateGenerator',\n 'tabContainerManager': 'ContainerManager',\n 'omsServerTime': 'Server Time',\n 'omsServerTimezone': 'Server Timezone',\n 'localBrowserTime': 'Local Time',\n 'localBrowserTimezone': 'Local Timezone',\n 'githubURL': 'GitHub Repo',\n 'docURL': 'Document Address',\n 'totalJobNum': 'total job Num',\n 'runningInstanceNum': 'running instance num',\n 'recentFailedInstanceNum': 'recent failed instance Num',\n 'workerNum': 'worker cluster size',\n 'workerAddress': 'worker address',\n 'cpuLoad': 'CPU Load',\n 'memoryLoad': 'Memory Load',\n 'diskLoad': 'Disk Load',\n // JobManage\n 'jobId': 'JobID',\n 'instanceId': 'InstanceID',\n 'jobName': 'JobName',\n 'scheduleInfo': 'ScheduleInfo',\n 'executeType': 'ExecuteType',\n 'processorType': 'ProcessorType',\n 'status': 'status',\n 'operation': 'operation',\n 'newJob': 'New Job',\n 'jobDescription': 'JobDescription',\n 'jobParams': 'JobParams',\n 'timeExpressionType': 'TimeExpressionType',\n 'timeExpressionPlaceHolder': 'cron expression or number(millions) for fix_rate/fix_delay job',\n 'executeConfig': 'ExecuteConfig',\n 'javaProcessorInfoPLH': 'classname, eg: com.github.kfcfans.DemoProcessor',\n 'containerProcessorInfoPLH': 'containerID#classname, eg: 1#com.github.kfcfans.DemoProcessor',\n 'shellProcessorInfoPLH': 'shell script',\n 'pythonProcessorInfoPLH': 'python script',\n 'runtimeConfig': 'RuntimeConfig',\n 'maxInstanceNum': 'MaxInstanceNum',\n 'threadConcurrency': 'ThreadConcurrency',\n 'timeout': 'TimeLimit (ms)',\n 'retryConfig': 'RetryConfig',\n 'taskRetryTimes': 'InstanceRetryTimes',\n 'subTaskRetryTimes': \"TaskRetryTimes\",\n 'workerConfig': 'WorkerConfig',\n 'minCPU': 'MinAvailableCPUCores',\n 'minMemory': 'MinMemory(GB)',\n 'minDisk': 'MinDisk(GB)',\n 'clusterConfig': 'ClusterConfig',\n 'designatedWorkerAddress': 'DesignatedWorkerAddress',\n 'designatedWorkerAddressPLH': 'empty for all worker or IP:Port,IP:Port ...',\n 'maxWorkerNum': 'MaxWorkerNum',\n 'maxWorkerNumPLH': '0 means no limit',\n 'alarmConfig': 'AlarmConfig',\n 'alarmSelectorPLH': 'select alarm recipient ',\n 'standalone': 'Standalone',\n 'broadcast': 'Broadcast',\n 'map': 'MAP',\n 'mapReduce': 'MapReduce',\n 'fixRate': 'Fix Rate (ms)',\n 'fixDelay': 'Fix Delay (ms)',\n 'workflow': 'workflow',\n 'onlineCronTool': 'online cron tool',\n 'javaContainer': 'Java(Container)',\n // JobInstance\n 'wfInstanceId': 'WorkflowInstanceId',\n 'normalInstance': 'normal instance',\n 'wfInstance': 'workflow instance',\n 'triggerTime': 'trigger time',\n 'finishedTime': 'finished time',\n 'log': 'log',\n 'runningTimes': 'running times',\n 'taskTrackerAddress': 'taskTracker address',\n 'startTime': 'start time',\n 'result': 'result',\n 'subTaskInfo': 'subTask info',\n 'secondlyJobHistory': 'secondlyJobHistory',\n 'subInstanceId': 'subInstanceId',\n // workflowManage\n 'wfId': 'WorkflowID',\n 'wfName': 'WorkflowName',\n 'newWorkflow': 'new workflow',\n 'wfDescription': 'description',\n 'importJob': 'import job',\n 'deleteJob': 'delete job',\n 'newStartPoint': 'new starting point',\n 'newEndPoint': 'new ending point',\n 'deleteEdge': 'delete edge',\n 'importJobTitle': \"select jobs\",\n 'wfTimeExpressionPLH': 'cron expression for CRON or empty for API',\n 'import': 'import',\n 'ntfClickNeedDeleteNode': 'Please click on the node you want to delete.',\n 'ntfClickStartPoint': 'Please click on the start node',\n 'ntfClickTargetPoint': 'Please click on the end node',\n 'ntfClickDeleteEdge': 'Please click on the edge you want to remove.',\n 'ntfAddStartPointFirst': 'Please add the starting point first!',\n 'ntfInvalidEdge': 'Illegal operation (same origin and destination)!',\n // workflowInstance\n 'wfTips': 'tips:Click on a node to view details of the job instance',\n 'ntfClickWaitingNode': 'Waiting for the upstream instances... No instances have been generated, and details cannot be viewed!',\n // 容器\n 'newContainer': 'new container',\n 'containerType': 'type',\n 'containerGitURL': 'Git URL',\n 'branchName': 'branch',\n 'username': 'username',\n 'password': 'password',\n 'containerId': 'ID',\n 'containerName': 'name',\n 'containerVersion': 'version',\n 'deployTime': 'deployed time',\n 'deploy': 'deploy',\n 'deployedWorkerList': 'worker list',\n 'uploadTips': 'Drag and drop or click on the file to upload it automatically',\n // 任务实例状态\n 'waitingDispatch': 'waiting dispatch',\n 'waitingWorkerReceive': 'waiting receive',\n 'running': 'running',\n 'stopped': 'stopped',\n 'wfWaiting': 'waiting',\n 'waitingUpstream': 'waiting upstream'\n }\n}, element_ui_lib_locale_lang_en__WEBPACK_IMPORTED_MODULE_1___default.a);\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (en);\n\n//# sourceURL=webpack:///./src/i18n/langs/en.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Users_zb_Documents_own_PowerJob_Console_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/esm/objectSpread2.js\");\n/* harmony import */ var element_ui_lib_locale_lang_en__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! element-ui/lib/locale/lang/en */ \"./node_modules/element-ui/lib/locale/lang/en.js\");\n/* harmony import */ var element_ui_lib_locale_lang_en__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(element_ui_lib_locale_lang_en__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\nvar en = Object(_Users_zb_Documents_own_PowerJob_Console_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({\n message: {\n 'save': 'save',\n 'cancel': 'cancel',\n 'refresh': 'refresh',\n 'query': 'query',\n 'reset': 'reset',\n 'keyword': 'keyword',\n 'run': 'run',\n 'edit': 'edit',\n 'delete': 'delete',\n 'success': 'success',\n 'failed': 'failed',\n 'detail': 'detail',\n 'download': 'download',\n 'stop': 'stop',\n 'back': 'back',\n 'all': 'ALL',\n // 欢迎界面\n 'appRegister': 'App Registration',\n 'userRegister': 'User Registration',\n 'appNameInputPLH': 'Enter The AppName',\n 'appName': 'AppName',\n 'appPassword': 'AppPassword',\n 'register': 'register',\n 'name': 'name',\n 'phone': 'phone',\n 'email': 'email',\n 'welcomeTitle': 'Welcome to use PowerJob!',\n 'login': 'Login',\n 'logout': 'Logout',\n 'changeAppInfo': 'Change AppInfo',\n 'newPassword': 'New Password',\n 'newPassword2': 'Check New Password',\n 'stayLogged': 'Keep me logged in',\n 'tabHome': 'Home',\n 'tabJobManage': 'JobManage',\n 'tabJobInstance': 'JobInstance',\n 'tabWorkflowManage': 'WorkflowManage',\n 'tabWfInstance': 'WorkflowInstance',\n 'tabContainerOps': 'ContainerOps',\n 'tabTemplate': 'TemplateGenerator',\n 'tabContainerManager': 'ContainerManager',\n 'omsServerTime': 'Server Time',\n 'omsServerTimezone': 'Server Timezone',\n 'localBrowserTime': 'Local Time',\n 'localBrowserTimezone': 'Local Timezone',\n 'githubURL': 'GitHub Repo',\n 'docURL': 'Document Address',\n 'totalJobNum': 'total job Num',\n 'runningInstanceNum': 'running instance num',\n 'recentFailedInstanceNum': 'recent failed instance Num',\n 'workerNum': 'worker cluster size',\n 'workerAddress': 'worker address',\n 'cpuLoad': 'CPU Load',\n 'memoryLoad': 'Memory Load',\n 'diskLoad': 'Disk Load',\n // JobManage\n 'jobId': 'JobID',\n 'instanceId': 'InstanceID',\n 'jobName': 'JobName',\n 'scheduleInfo': 'ScheduleInfo',\n 'executeType': 'ExecuteType',\n 'processorType': 'ProcessorType',\n 'status': 'status',\n 'operation': 'operation',\n 'newJob': 'New Job',\n 'jobDescription': 'JobDescription',\n 'jobParams': 'JobParams',\n 'timeExpressionType': 'TimeExpressionType',\n 'timeExpressionPlaceHolder': 'cron expression or number(millions) for fix_rate/fix_delay job',\n 'executeConfig': 'ExecuteConfig',\n 'javaProcessorInfoPLH': 'classname, eg: com.github.kfcfans.DemoProcessor',\n 'containerProcessorInfoPLH': 'containerID#classname, eg: 1#com.github.kfcfans.DemoProcessor',\n 'shellProcessorInfoPLH': 'shell script',\n 'pythonProcessorInfoPLH': 'python script',\n 'runtimeConfig': 'RuntimeConfig',\n 'maxInstanceNum': 'MaxInstanceNum',\n 'threadConcurrency': 'ThreadConcurrency',\n 'timeout': 'TimeLimit (ms)',\n 'retryConfig': 'RetryConfig',\n 'taskRetryTimes': 'InstanceRetryTimes',\n 'subTaskRetryTimes': \"TaskRetryTimes\",\n 'workerConfig': 'WorkerConfig',\n 'minCPU': 'MinAvailableCPUCores',\n 'minMemory': 'MinMemory(GB)',\n 'minDisk': 'MinDisk(GB)',\n 'clusterConfig': 'ClusterConfig',\n 'designatedWorkerAddress': 'DesignatedWorkerAddress',\n 'designatedWorkerAddressPLH': 'empty for all worker or IP:Port,IP:Port ...',\n 'maxWorkerNum': 'MaxWorkerNum',\n 'maxWorkerNumPLH': '0 means no limit',\n 'alarmConfig': 'AlarmConfig',\n 'alarmSelectorPLH': 'select alarm recipient ',\n 'standalone': 'Standalone',\n 'broadcast': 'Broadcast',\n 'map': 'MAP',\n 'mapReduce': 'MapReduce',\n 'fixRate': 'Fix Rate (ms)',\n 'fixDelay': 'Fix Delay (ms)',\n 'workflow': 'workflow',\n 'onlineCronTool': 'online cron tool',\n 'javaContainer': 'Java(Container)',\n // JobInstance\n 'wfInstanceId': 'WorkflowInstanceId',\n 'normalInstance': 'normal instance',\n 'wfInstance': 'workflow instance',\n 'triggerTime': 'trigger time',\n 'finishedTime': 'finished time',\n 'log': 'log',\n 'runningTimes': 'running times',\n 'taskTrackerAddress': 'taskTracker address',\n 'startTime': 'start time',\n 'expectedTriggerTime': 'expected trigger time',\n 'result': 'result',\n 'subTaskInfo': 'task info',\n 'secondlyJobHistory': 'secondlyJobHistory',\n 'subInstanceId': 'subInstanceId',\n // workflowManage\n 'wfId': 'WorkflowID',\n 'wfName': 'WorkflowName',\n 'newWorkflow': 'new workflow',\n 'wfDescription': 'description',\n 'importJob': 'import job',\n 'deleteJob': 'delete job',\n 'newStartPoint': 'new starting point',\n 'newEndPoint': 'new ending point',\n 'deleteEdge': 'delete edge',\n 'importJobTitle': \"select jobs\",\n 'wfTimeExpressionPLH': 'cron expression for CRON or empty for API',\n 'import': 'import',\n 'ntfClickNeedDeleteNode': 'Please click on the node you want to delete.',\n 'ntfClickStartPoint': 'Please click on the start node',\n 'ntfClickTargetPoint': 'Please click on the end node',\n 'ntfClickDeleteEdge': 'Please click on the edge you want to remove.',\n 'ntfAddStartPointFirst': 'Please add the starting point first!',\n 'ntfInvalidEdge': 'Illegal operation (same origin and destination)!',\n // workflowInstance\n 'wfTips': 'tips:Click on a node to view details of the job instance',\n 'ntfClickWaitingNode': 'Waiting for the upstream instances... No instances have been generated, and details cannot be viewed!',\n // 容器\n 'newContainer': 'new container',\n 'containerType': 'type',\n 'containerGitURL': 'Git URL',\n 'branchName': 'branch',\n 'username': 'username',\n 'password': 'password',\n 'containerId': 'ID',\n 'containerName': 'name',\n 'containerVersion': 'version',\n 'deployTime': 'deployed time',\n 'deploy': 'deploy',\n 'deployedWorkerList': 'worker list',\n 'uploadTips': 'Drag and drop or click on the file to upload it automatically',\n // 任务实例状态\n 'waitingDispatch': 'waiting dispatch',\n 'waitingWorkerReceive': 'waiting receive',\n 'running': 'running',\n 'stopped': 'stopped',\n 'canceled': 'canceled',\n 'wfWaiting': 'waiting',\n 'waitingUpstream': 'waiting upstream'\n }\n}, element_ui_lib_locale_lang_en__WEBPACK_IMPORTED_MODULE_1___default.a);\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (en);\n\n//# sourceURL=webpack:///./src/i18n/langs/en.js?");
/***/ }),
@@ -712,7 +712,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _en_
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.object.to-string */ \"./node_modules/core-js/modules/es.object.to-string.js\");\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_es_regexp_exec__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/es.regexp.exec */ \"./node_modules/core-js/modules/es.regexp.exec.js\");\n/* harmony import */ var core_js_modules_es_regexp_exec__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_regexp_exec__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var core_js_modules_es_regexp_to_string__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! core-js/modules/es.regexp.to-string */ \"./node_modules/core-js/modules/es.regexp.to-string.js\");\n/* harmony import */ var core_js_modules_es_regexp_to_string__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_regexp_to_string__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var core_js_modules_es_string_search__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! core-js/modules/es.string.search */ \"./node_modules/core-js/modules/es.string.search.js\");\n/* harmony import */ var core_js_modules_es_string_search__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_string_search__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_array_iterator_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./node_modules/core-js/modules/es.array.iterator.js */ \"./node_modules/core-js/modules/es.array.iterator.js\");\n/* harmony import */ var _Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_array_iterator_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_array_iterator_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./node_modules/core-js/modules/es.promise.js */ \"./node_modules/core-js/modules/es.promise.js\");\n/* harmony import */ var _Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_object_assign_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./node_modules/core-js/modules/es.object.assign.js */ \"./node_modules/core-js/modules/es.object.assign.js\");\n/* harmony import */ var _Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_object_assign_js__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_object_assign_js__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_promise_finally_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./node_modules/core-js/modules/es.promise.finally.js */ \"./node_modules/core-js/modules/es.promise.finally.js\");\n/* harmony import */ var _Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_promise_finally_js__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_Users_tjq_Desktop_DistributeCompute_PowerJob_Console_node_modules_core_js_modules_es_promise_finally_js__WEBPACK_IMPORTED_MODULE_7__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm.js\");\n/* harmony import */ var _App_vue__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./App.vue */ \"./src/App.vue\");\n/* harmony import */ var element_ui__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! element-ui */ \"./node_modules/element-ui/lib/element-ui.common.js\");\n/* harmony import */ var element_ui__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(element_ui__WEBPACK_IMPORTED_MODULE_10__);\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./styles.scss */ \"./src/styles.scss\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_11___default = /*#__PURE__*/__webpack_require__.n(_styles_scss__WEBPACK_IMPORTED_MODULE_11__);\n/* harmony import */ var _plugins_element_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./plugins/element.js */ \"./src/plugins/element.js\");\n/* harmony import */ var _i18n_i18n__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./i18n/i18n */ \"./src/i18n/i18n.js\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! axios */ \"./node_modules/axios/index.js\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_14___default = /*#__PURE__*/__webpack_require__.n(axios__WEBPACK_IMPORTED_MODULE_14__);\n/* harmony import */ var flyio__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! flyio */ \"./node_modules/flyio/index.js\");\n/* harmony import */ var flyio__WEBPACK_IMPORTED_MODULE_15___default = /*#__PURE__*/__webpack_require__.n(flyio__WEBPACK_IMPORTED_MODULE_15__);\n/* harmony import */ var _router__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./router */ \"./src/router.js\");\n/* harmony import */ var _store__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./store */ \"./src/store.js\");\n/* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./common */ \"./src/common.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n // axios 负责统一拦截处理 ResultDTO,fly 负责处理不需要拦截的请求\n\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_8__[\"default\"].use(element_ui__WEBPACK_IMPORTED_MODULE_10___default.a); // let baseURL = \"http://139.224.83.134:7700\";\n\nvar baseURL = \"/\";\nvar timeout = 5000;\nvue__WEBPACK_IMPORTED_MODULE_8__[\"default\"].prototype.common = _common__WEBPACK_IMPORTED_MODULE_18__[\"default\"];\n/* ******* axios config ******* */\n\nvue__WEBPACK_IMPORTED_MODULE_8__[\"default\"].prototype.axios = axios__WEBPACK_IMPORTED_MODULE_14___default.a;\naxios__WEBPACK_IMPORTED_MODULE_14___default.a.defaults.baseURL = baseURL;\naxios__WEBPACK_IMPORTED_MODULE_14___default.a.defaults.timeout = timeout;\n/* ******* fly.io config ******* */\n\nvue__WEBPACK_IMPORTED_MODULE_8__[\"default\"].prototype.flyio = flyio__WEBPACK_IMPORTED_MODULE_15___default.a;\nflyio__WEBPACK_IMPORTED_MODULE_15___default.a.config.baseURL = baseURL;\nflyio__WEBPACK_IMPORTED_MODULE_15___default.a.config.timeout = timeout;\nvue__WEBPACK_IMPORTED_MODULE_8__[\"default\"].config.productionTip = false;\nnew vue__WEBPACK_IMPORTED_MODULE_8__[\"default\"]({\n router: _router__WEBPACK_IMPORTED_MODULE_16__[\"default\"],\n store: _store__WEBPACK_IMPORTED_MODULE_17__[\"default\"],\n i18n: _i18n_i18n__WEBPACK_IMPORTED_MODULE_13__[\"default\"],\n render: function render(h) {\n return h(_App_vue__WEBPACK_IMPORTED_MODULE_9__[\"default\"]);\n }\n}).$mount('#app'); //请求发送拦截,没有 appId 要求重新 \"登录\"\n\naxios__WEBPACK_IMPORTED_MODULE_14___default.a.interceptors.request.use(function (request) {\n var url = request.url;\n var isListAppInfo = url.search(\"/appInfo/list\") !== -1;\n var isAppRegister = url.search(\"/appInfo/save\") !== -1;\n var isUserRegister = url.search(\"/user/save\") !== -1;\n var isAssertAppInfo = url.search(\"/appInfo/assert\") !== -1;\n\n if (isListAppInfo || isAppRegister || isUserRegister || isAssertAppInfo) {\n return request;\n }\n\n var appId = _store__WEBPACK_IMPORTED_MODULE_17__[\"default\"].state.appInfo.id;\n\n if (appId === undefined || appId === null) {\n _router__WEBPACK_IMPORTED_MODULE_16__[\"default\"].push(\"/\");\n return Promise.reject(\"no appId\");\n }\n\n return request;\n}, function (error) {\n // Do something with request error\n return Promise.reject(error);\n}); // 请求返回拦截,封装公共处理逻辑\n\naxios__WEBPACK_IMPORTED_MODULE_14___default.a.interceptors.response.use(function (response) {\n if (response.data.success === true) {\n return response.data.data;\n }\n\n element_ui__WEBPACK_IMPORTED_MODULE_10__[\"Message\"].warning(\"ERROR:\" + response.data.message);\n return Promise.reject(response.data.msg);\n}, function (error) {\n element_ui__WEBPACK_IMPORTED_MODULE_10__[\"Message\"].error(error.toString());\n return Promise.reject(error);\n});\n/* harmony default export */ __webpack_exports__[\"default\"] = (baseURL);\n\n//# sourceURL=webpack:///./src/main.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.object.to-string */ \"./node_modules/core-js/modules/es.object.to-string.js\");\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_es_regexp_exec__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/es.regexp.exec */ \"./node_modules/core-js/modules/es.regexp.exec.js\");\n/* harmony import */ var core_js_modules_es_regexp_exec__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_regexp_exec__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var core_js_modules_es_regexp_to_string__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! core-js/modules/es.regexp.to-string */ \"./node_modules/core-js/modules/es.regexp.to-string.js\");\n/* harmony import */ var core_js_modules_es_regexp_to_string__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_regexp_to_string__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var core_js_modules_es_string_search__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! core-js/modules/es.string.search */ \"./node_modules/core-js/modules/es.string.search.js\");\n/* harmony import */ var core_js_modules_es_string_search__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_string_search__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_array_iterator_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./node_modules/core-js/modules/es.array.iterator.js */ \"./node_modules/core-js/modules/es.array.iterator.js\");\n/* harmony import */ var _Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_array_iterator_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_array_iterator_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./node_modules/core-js/modules/es.promise.js */ \"./node_modules/core-js/modules/es.promise.js\");\n/* harmony import */ var _Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_promise_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_object_assign_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./node_modules/core-js/modules/es.object.assign.js */ \"./node_modules/core-js/modules/es.object.assign.js\");\n/* harmony import */ var _Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_object_assign_js__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_object_assign_js__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_promise_finally_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./node_modules/core-js/modules/es.promise.finally.js */ \"./node_modules/core-js/modules/es.promise.finally.js\");\n/* harmony import */ var _Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_promise_finally_js__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_Users_zb_Documents_own_PowerJob_Console_node_modules_core_js_modules_es_promise_finally_js__WEBPACK_IMPORTED_MODULE_7__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm.js\");\n/* harmony import */ var _App_vue__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./App.vue */ \"./src/App.vue\");\n/* harmony import */ var element_ui__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! element-ui */ \"./node_modules/element-ui/lib/element-ui.common.js\");\n/* harmony import */ var element_ui__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(element_ui__WEBPACK_IMPORTED_MODULE_10__);\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./styles.scss */ \"./src/styles.scss\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_11___default = /*#__PURE__*/__webpack_require__.n(_styles_scss__WEBPACK_IMPORTED_MODULE_11__);\n/* harmony import */ var _plugins_element_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./plugins/element.js */ \"./src/plugins/element.js\");\n/* harmony import */ var _i18n_i18n__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./i18n/i18n */ \"./src/i18n/i18n.js\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! axios */ \"./node_modules/axios/index.js\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_14___default = /*#__PURE__*/__webpack_require__.n(axios__WEBPACK_IMPORTED_MODULE_14__);\n/* harmony import */ var flyio__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! flyio */ \"./node_modules/flyio/index.js\");\n/* harmony import */ var flyio__WEBPACK_IMPORTED_MODULE_15___default = /*#__PURE__*/__webpack_require__.n(flyio__WEBPACK_IMPORTED_MODULE_15__);\n/* harmony import */ var _router__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./router */ \"./src/router.js\");\n/* harmony import */ var _store__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./store */ \"./src/store.js\");\n/* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./common */ \"./src/common.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n // axios 负责统一拦截处理 ResultDTO,fly 负责处理不需要拦截的请求\n\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_8__[\"default\"].use(element_ui__WEBPACK_IMPORTED_MODULE_10___default.a); // let baseURL = \"http://139.224.83.134:7700\";\n\nvar baseURL = \"/\";\nvar timeout = 5000;\nvue__WEBPACK_IMPORTED_MODULE_8__[\"default\"].prototype.common = _common__WEBPACK_IMPORTED_MODULE_18__[\"default\"];\n/* ******* axios config ******* */\n\nvue__WEBPACK_IMPORTED_MODULE_8__[\"default\"].prototype.axios = axios__WEBPACK_IMPORTED_MODULE_14___default.a;\naxios__WEBPACK_IMPORTED_MODULE_14___default.a.defaults.baseURL = baseURL;\naxios__WEBPACK_IMPORTED_MODULE_14___default.a.defaults.timeout = timeout;\n/* ******* fly.io config ******* */\n\nvue__WEBPACK_IMPORTED_MODULE_8__[\"default\"].prototype.flyio = flyio__WEBPACK_IMPORTED_MODULE_15___default.a;\nflyio__WEBPACK_IMPORTED_MODULE_15___default.a.config.baseURL = baseURL;\nflyio__WEBPACK_IMPORTED_MODULE_15___default.a.config.timeout = timeout;\nvue__WEBPACK_IMPORTED_MODULE_8__[\"default\"].config.productionTip = false;\nnew vue__WEBPACK_IMPORTED_MODULE_8__[\"default\"]({\n router: _router__WEBPACK_IMPORTED_MODULE_16__[\"default\"],\n store: _store__WEBPACK_IMPORTED_MODULE_17__[\"default\"],\n i18n: _i18n_i18n__WEBPACK_IMPORTED_MODULE_13__[\"default\"],\n render: function render(h) {\n return h(_App_vue__WEBPACK_IMPORTED_MODULE_9__[\"default\"]);\n }\n}).$mount('#app'); //请求发送拦截,没有 appId 要求重新 \"登录\"\n\naxios__WEBPACK_IMPORTED_MODULE_14___default.a.interceptors.request.use(function (request) {\n var url = request.url;\n var isListAppInfo = url.search(\"/appInfo/list\") !== -1;\n var isAppRegister = url.search(\"/appInfo/save\") !== -1;\n var isUserRegister = url.search(\"/user/save\") !== -1;\n var isAssertAppInfo = url.search(\"/appInfo/assert\") !== -1;\n\n if (isListAppInfo || isAppRegister || isUserRegister || isAssertAppInfo) {\n return request;\n }\n\n var appId = _store__WEBPACK_IMPORTED_MODULE_17__[\"default\"].state.appInfo.id;\n\n if (appId === undefined || appId === null) {\n _router__WEBPACK_IMPORTED_MODULE_16__[\"default\"].push(\"/\");\n return Promise.reject(\"no appId\");\n }\n\n return request;\n}, function (error) {\n // Do something with request error\n return Promise.reject(error);\n}); // 请求返回拦截,封装公共处理逻辑\n\naxios__WEBPACK_IMPORTED_MODULE_14___default.a.interceptors.response.use(function (response) {\n if (response.data.success === true) {\n return response.data.data;\n }\n\n element_ui__WEBPACK_IMPORTED_MODULE_10__[\"Message\"].warning(\"ERROR:\" + response.data.message);\n return Promise.reject(response.data.msg);\n}, function (error) {\n element_ui__WEBPACK_IMPORTED_MODULE_10__[\"Message\"].error(error.toString());\n return Promise.reject(error);\n});\n/* harmony default export */ __webpack_exports__[\"default\"] = (baseURL);\n\n//# sourceURL=webpack:///./src/main.js?");
/***/ }),
diff --git a/powerjob-server/src/test/java/com/github/kfcfans/powerjob/server/test/UtilsTest.java b/powerjob-server/src/test/java/com/github/kfcfans/powerjob/server/test/UtilsTest.java
index 0703432f..8350e6e5 100644
--- a/powerjob-server/src/test/java/com/github/kfcfans/powerjob/server/test/UtilsTest.java
+++ b/powerjob-server/src/test/java/com/github/kfcfans/powerjob/server/test/UtilsTest.java
@@ -5,6 +5,7 @@ import com.github.kfcfans.powerjob.server.common.utils.timewheel.HashedWheelTime
import com.github.kfcfans.powerjob.server.common.utils.timewheel.TimerFuture;
import com.github.kfcfans.powerjob.server.common.utils.timewheel.TimerTask;
import com.google.common.collect.Lists;
+import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import java.util.Date;
@@ -82,4 +83,12 @@ public class UtilsTest {
public void testTZ() {
System.out.println(TimeZone.getDefault());
}
+
+ @Test
+ public void testStringUtils() {
+ String goodAppName = "powerjob-server";
+ String appName = "powerjob-server ";
+ System.out.println(StringUtils.containsWhitespace(goodAppName));
+ System.out.println(StringUtils.containsWhitespace(appName));
+ }
}
diff --git a/powerjob-worker-agent/pom.xml b/powerjob-worker-agent/pom.xml
index 4b4c7db2..82211504 100644
--- a/powerjob-worker-agent/pom.xml
+++ b/powerjob-worker-agent/pom.xml
@@ -10,12 +10,12 @@
4.0.0
powerjob-worker-agent
- 3.2.0
+ 3.2.1
jar
- 3.2.0
+ 3.2.1
1.2.3
4.3.2
diff --git a/powerjob-worker-samples/pom.xml b/powerjob-worker-samples/pom.xml
index e11ca2cc..e2500e5a 100644
--- a/powerjob-worker-samples/pom.xml
+++ b/powerjob-worker-samples/pom.xml
@@ -10,11 +10,11 @@
4.0.0
powerjob-worker-samples
- 3.2.0
+ 3.2.1
2.2.6.RELEASE
- 3.2.0
+ 3.2.1
1.2.68
diff --git a/powerjob-worker-spring-boot-starter/pom.xml b/powerjob-worker-spring-boot-starter/pom.xml
new file mode 100644
index 00000000..1e7eb819
--- /dev/null
+++ b/powerjob-worker-spring-boot-starter/pom.xml
@@ -0,0 +1,45 @@
+
+
+
+ powerjob
+ com.github.kfcfans
+ 1.0.0
+
+
+ 4.0.0
+ powerjob-worker-spring-boot-starter
+ 3.2.1
+ jar
+
+
+ 3.2.1
+ 2.2.6.RELEASE
+
+
+
+
+
+ com.github.kfcfans
+ powerjob-worker
+ ${powerjob.worker.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+ ${springboot.version}
+ compile
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ ${springboot.version}
+ test
+
+
+
+
+
\ No newline at end of file
diff --git a/powerjob-worker-spring-boot-starter/src/main/java/com/github/kfcfans/powerjob/worker/autoconfigure/PowerJobAutoConfiguration.java b/powerjob-worker-spring-boot-starter/src/main/java/com/github/kfcfans/powerjob/worker/autoconfigure/PowerJobAutoConfiguration.java
new file mode 100644
index 00000000..6f6000c4
--- /dev/null
+++ b/powerjob-worker-spring-boot-starter/src/main/java/com/github/kfcfans/powerjob/worker/autoconfigure/PowerJobAutoConfiguration.java
@@ -0,0 +1,50 @@
+package com.github.kfcfans.powerjob.worker.autoconfigure;
+
+import com.github.kfcfans.powerjob.common.utils.CommonUtils;
+import com.github.kfcfans.powerjob.worker.OhMyWorker;
+import com.github.kfcfans.powerjob.worker.common.OhMyConfig;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * PowerJob 自动装配
+ *
+ * @author songyinyin
+ * @since 2020/7/26 16:37
+ */
+@Configuration
+@EnableConfigurationProperties(PowerJobProperties.class)
+public class PowerJobAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public OhMyWorker initPowerJob(PowerJobProperties properties) {
+
+ // 服务器HTTP地址(端口号为 server.port,而不是 ActorSystem port),请勿添加任何前缀(http://)
+ CommonUtils.requireNonNull(properties.getServerAddress(), "serverAddress can't be empty!");
+ List serverAddress = Arrays.asList(properties.getServerAddress().split(","));
+
+ // 1. 创建配置文件
+ OhMyConfig config = new OhMyConfig();
+ // 可以不显式设置,默认值 27777
+ config.setPort(properties.getAkkaPort());
+ // appName,需要提前在控制台注册,否则启动报错
+ config.setAppName(properties.getAppName());
+ config.setServerAddress(serverAddress);
+ // 如果没有大型 Map/MapReduce 的需求,建议使用内存来加速计算
+ // 有大型 Map/MapReduce 需求,可能产生大量子任务(Task)的场景,请使用 DISK,否则妥妥的 OutOfMemory
+ config.setStoreStrategy(properties.getStoreStrategy());
+ // 启动测试模式,true情况下,不再尝试连接 server 并验证appName
+ config.setEnableTestMode(properties.isEnableTestMode());
+
+ // 2. 创建 Worker 对象,设置配置文件
+ OhMyWorker ohMyWorker = new OhMyWorker();
+ ohMyWorker.setConfig(config);
+ return ohMyWorker;
+ }
+}
diff --git a/powerjob-worker-spring-boot-starter/src/main/java/com/github/kfcfans/powerjob/worker/autoconfigure/PowerJobProperties.java b/powerjob-worker-spring-boot-starter/src/main/java/com/github/kfcfans/powerjob/worker/autoconfigure/PowerJobProperties.java
new file mode 100644
index 00000000..b8cf30b9
--- /dev/null
+++ b/powerjob-worker-spring-boot-starter/src/main/java/com/github/kfcfans/powerjob/worker/autoconfigure/PowerJobProperties.java
@@ -0,0 +1,44 @@
+package com.github.kfcfans.powerjob.worker.autoconfigure;
+
+import com.github.kfcfans.powerjob.common.RemoteConstant;
+import com.github.kfcfans.powerjob.worker.common.constants.StoreStrategy;
+import com.github.kfcfans.powerjob.worker.core.processor.ProcessResult;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * PowerJob 配置项
+ *
+ * @author songyinyin
+ * @since 2020/7/26 16:37
+ */
+@Data
+@ConfigurationProperties(prefix = "powerjob")
+public class PowerJobProperties {
+ /**
+ * 应用名称,需要提前在控制台注册,否则启动报错
+ */
+ private String appName;
+ /**
+ * 启动 akka 端口
+ */
+ private int akkaPort = RemoteConstant.DEFAULT_WORKER_PORT;
+ /**
+ * 调度服务器地址,ip:port 或 域名,多个用英文逗号分隔
+ */
+ private String serverAddress;
+ /**
+ * 本地持久化方式,默认使用磁盘
+ */
+ private StoreStrategy storeStrategy = StoreStrategy.DISK;
+ /**
+ * 最大返回值长度,超过会被截断
+ * {@link ProcessResult}#msg 的最大长度
+ */
+ private int maxResultLength = 8096;
+ /**
+ * 启动测试模式,true情况下,不再尝试连接 server 并验证appName。
+ * true -> 用于本地写单元测试调试; false -> 默认值,标准模式
+ */
+ private boolean enableTestMode = false;
+}
diff --git a/powerjob-worker-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json b/powerjob-worker-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json
new file mode 100644
index 00000000..1fbedb0a
--- /dev/null
+++ b/powerjob-worker-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json
@@ -0,0 +1,50 @@
+{
+ "groups": [
+ {
+ "name": "powerjob",
+ "type": "com.github.kfcfans.powerjob.worker.autoconfigure.PowerJobProperties",
+ "sourceType": "com.github.kfcfans.powerjob.worker.autoconfigure.PowerJobProperties"
+ }
+ ],
+ "properties": [
+ {
+ "name": "powerjob.app-name",
+ "type": "java.lang.String",
+ "description": "应用名称,需要提前在控制台注册,否则启动报错",
+ "sourceType": "com.github.kfcfans.powerjob.worker.autoconfigure.PowerJobProperties"
+ },
+ {
+ "name": "powerjob.max-result-length",
+ "type": "java.lang.Integer",
+ "description": "最大返回值长度,超过会被截断 {@link ProcessResult}#msg 的最大长度",
+ "sourceType": "com.github.kfcfans.powerjob.worker.autoconfigure.PowerJobProperties",
+ "defaultValue": 8096
+ },
+ {
+ "name": "powerjob.akka-port",
+ "type": "java.lang.Integer",
+ "description": "启动 akka 端口",
+ "sourceType": "com.github.kfcfans.powerjob.worker.autoconfigure.PowerJobProperties"
+ },
+ {
+ "name": "powerjob.server-address",
+ "type": "java.lang.String",
+ "description": "调度服务器地址,ip:port 或 域名,多值用英文逗号分隔",
+ "sourceType": "com.github.kfcfans.powerjob.worker.autoconfigure.PowerJobProperties"
+ },
+ {
+ "name": "powerjob.store-strategy",
+ "type": "com.github.kfcfans.powerjob.worker.common.constants.StoreStrategy",
+ "description": "本地持久化方式,默认使用磁盘",
+ "sourceType": "com.github.kfcfans.powerjob.worker.autoconfigure.PowerJobProperties"
+ },
+ {
+ "name": "powerjob.enable-test-mode",
+ "type": "java.lang.Boolean",
+ "description": "启动测试模式,true情况下,不再尝试连接 server 并验证appName。true -> 用于本地写单元测试调试; false -> 默认值,标准模式",
+ "sourceType": "com.github.kfcfans.powerjob.worker.autoconfigure.PowerJobProperties",
+ "defaultValue": false
+ }
+ ],
+ "hints": []
+}
\ No newline at end of file
diff --git a/powerjob-worker-spring-boot-starter/src/main/resources/META-INF/spring.factories b/powerjob-worker-spring-boot-starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000..19eea33f
--- /dev/null
+++ b/powerjob-worker-spring-boot-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+ com.github.kfcfans.powerjob.worker.autoconfigure.PowerJobAutoConfiguration
\ No newline at end of file
diff --git a/powerjob-worker-spring-boot-starter/src/test/java/com/github/kfcfans/powerjob/worker/autoconfigure/PowerJobAutoConfigurationTest.java b/powerjob-worker-spring-boot-starter/src/test/java/com/github/kfcfans/powerjob/worker/autoconfigure/PowerJobAutoConfigurationTest.java
new file mode 100644
index 00000000..dd90d395
--- /dev/null
+++ b/powerjob-worker-spring-boot-starter/src/test/java/com/github/kfcfans/powerjob/worker/autoconfigure/PowerJobAutoConfigurationTest.java
@@ -0,0 +1,22 @@
+package com.github.kfcfans.powerjob.worker.autoconfigure;
+
+import com.github.kfcfans.powerjob.worker.OhMyWorker;
+import org.junit.Assert;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableAutoConfiguration
+class PowerJobAutoConfigurationTest {
+
+ @Test
+ void testAutoConfiguration() {
+ ConfigurableApplicationContext run = SpringApplication.run(PowerJobAutoConfigurationTest.class);
+ OhMyWorker worker = run.getBean(OhMyWorker.class);
+ Assert.assertNotNull(worker);
+ }
+
+}
diff --git a/powerjob-worker-spring-boot-starter/src/test/resources/application.properties b/powerjob-worker-spring-boot-starter/src/test/resources/application.properties
new file mode 100644
index 00000000..fbcb42fa
--- /dev/null
+++ b/powerjob-worker-spring-boot-starter/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+
+powerjob.enable-test-mode=true
\ No newline at end of file
diff --git a/powerjob-worker/pom.xml b/powerjob-worker/pom.xml
index e4b55ef1..63661bc0 100644
--- a/powerjob-worker/pom.xml
+++ b/powerjob-worker/pom.xml
@@ -10,12 +10,12 @@
4.0.0
powerjob-worker
- 3.2.0
+ 3.2.1
jar
5.2.4.RELEASE
- 3.2.0
+ 3.2.1
1.4.200
3.4.2
5.6.1
diff --git a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/OhMyWorker.java b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/OhMyWorker.java
index 90722fee..5b43a04c 100644
--- a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/OhMyWorker.java
+++ b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/OhMyWorker.java
@@ -21,6 +21,7 @@ import com.github.kfcfans.powerjob.worker.background.ServerDiscoveryService;
import com.github.kfcfans.powerjob.worker.background.WorkerHealthReporter;
import com.github.kfcfans.powerjob.worker.common.OhMyConfig;
import com.github.kfcfans.powerjob.worker.common.OmsBannerPrinter;
+import com.github.kfcfans.powerjob.worker.common.utils.OmsWorkerFileUtils;
import com.github.kfcfans.powerjob.worker.common.utils.SpringUtils;
import com.github.kfcfans.powerjob.worker.persistence.TaskPersistenceService;
import com.google.common.base.Stopwatch;
@@ -30,6 +31,7 @@ import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
@@ -37,6 +39,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.StringUtils;
+import java.io.File;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executors;
@@ -80,6 +83,7 @@ public class OhMyWorker implements ApplicationContextAware, InitializingBean, Di
Stopwatch stopwatch = Stopwatch.createStarted();
log.info("[OhMyWorker] start to initialize OhMyWorker...");
try {
+ pre();
OmsBannerPrinter.print();
// 校验 appName
if (!config.isEnableTestMode()) {
@@ -179,4 +183,14 @@ public class OhMyWorker implements ApplicationContextAware, InitializingBean, Di
public void destroy() throws Exception {
timingPool.shutdownNow();
}
+
+ private static void pre() {
+ // 删除历史遗留的 H2 数据库文件
+ String h2Path = OmsWorkerFileUtils.getH2Dir();
+ try {
+ FileUtils.forceDeleteOnExit(new File(h2Path));
+ }catch (Exception e) {
+ log.warn("[PowerJob] delete h2 workspace({}) failed, if worker can't startup successfully, please delete it manually", h2Path, e);
+ }
+ }
}
diff --git a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/common/utils/OmsWorkerFileUtils.java b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/common/utils/OmsWorkerFileUtils.java
index 2cf9884b..823e5504 100644
--- a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/common/utils/OmsWorkerFileUtils.java
+++ b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/common/utils/OmsWorkerFileUtils.java
@@ -18,4 +18,8 @@ public class OmsWorkerFileUtils {
public static String getContainerDir() {
return WORKER_DIR + "container/";
}
+
+ public static String getH2Dir() {
+ return WORKER_DIR + "h2/";
+ }
}
diff --git a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/container/OmsContainerFactory.java b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/container/OmsContainerFactory.java
index 2eb289c4..a8640054 100644
--- a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/container/OmsContainerFactory.java
+++ b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/container/OmsContainerFactory.java
@@ -124,7 +124,7 @@ public class OmsContainerFactory {
oldContainer.destroy();
}
- }catch (Exception e) {
+ } catch (Exception e) {
log.error("[OmsContainer-{}] deployContainer(name={},version={}) failed.", containerId, containerName, version, e);
// 如果部署失败,则删除该 jar(本次失败可能是下载jar出错导致,不删除会导致这个版本永久无法重新部署)
CommonUtils.executeIgnoreException(() -> FileUtils.forceDelete(jarFile));
diff --git a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/core/processor/built/ScriptProcessor.java b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/core/processor/built/ScriptProcessor.java
index 402b39ec..2780f86c 100644
--- a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/core/processor/built/ScriptProcessor.java
+++ b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/core/processor/built/ScriptProcessor.java
@@ -96,7 +96,9 @@ public abstract class ScriptProcessor implements BasicProcessor {
}
String result = String.format("[INPUT]: %s;[ERROR]: %s", inputSB.toString(), errorSB.toString());
- return new ProcessResult(true, result);
+ // 0 代表正常退出
+ int exitValue = process.exitValue();
+ return new ProcessResult(exitValue == 0, result);
}catch (InterruptedException ie) {
omsLogger.info("SYSTEM===> ScriptProcessor has been interrupted");
return new ProcessResult(false, "Interrupted");
diff --git a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/core/tracker/task/FrequentTaskTracker.java b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/core/tracker/task/FrequentTaskTracker.java
index 3e484b84..00cd28cc 100644
--- a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/core/tracker/task/FrequentTaskTracker.java
+++ b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/core/tracker/task/FrequentTaskTracker.java
@@ -171,11 +171,13 @@ public class FrequentTaskTracker extends TaskTracker {
newRootTask.setLastReportTime(-1L);
// 判断是否超出最大执行实例数
- if (timeExpressionType == TimeExpressionType.FIX_RATE) {
- if (subInstanceId2TimeHolder.size() > maxInstanceNum) {
- log.warn("[TaskTracker-{}] cancel to launch the subInstance({}) due to too much subInstance is running.", instanceId, subInstanceId);
- processFinishedSubInstance(subInstanceId, false, "TOO_MUCH_INSTANCE");
- return;
+ if (maxInstanceNum > 0) {
+ if (timeExpressionType == TimeExpressionType.FIX_RATE) {
+ if (subInstanceId2TimeHolder.size() > maxInstanceNum) {
+ log.warn("[TaskTracker-{}] cancel to launch the subInstance({}) due to too much subInstance is running.", instanceId, subInstanceId);
+ processFinishedSubInstance(subInstanceId, false, "TOO_MUCH_INSTANCE");
+ return;
+ }
}
}
diff --git a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/persistence/ConnectionFactory.java b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/persistence/ConnectionFactory.java
index a941c34f..aa630a9b 100644
--- a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/persistence/ConnectionFactory.java
+++ b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/persistence/ConnectionFactory.java
@@ -2,6 +2,7 @@ package com.github.kfcfans.powerjob.worker.persistence;
import com.github.kfcfans.powerjob.worker.OhMyWorker;
import com.github.kfcfans.powerjob.worker.common.constants.StoreStrategy;
+import com.github.kfcfans.powerjob.worker.common.utils.OmsWorkerFileUtils;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
@@ -19,8 +20,8 @@ public class ConnectionFactory {
private static volatile DataSource dataSource;
- private static final String DISK_JDBC_URL = "jdbc:h2:file:~/powerjob/h2/oms_worker_db";
- private static final String MEMORY_JDBC_URL = "jdbc:h2:mem:~/powerjob/h2/oms_worker_db";
+ private static final String DISK_JDBC_URL = String.format("jdbc:h2:file:%spowerjob_worker_db", OmsWorkerFileUtils.getH2Dir());
+ private static final String MEMORY_JDBC_URL = String.format("jdbc:h2:mem:%spowerjob_worker_db", OmsWorkerFileUtils.getH2Dir());
public static Connection getConnection() throws SQLException {
return getDataSource().getConnection();
diff --git a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/persistence/TaskDO.java b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/persistence/TaskDO.java
index ef5041d6..33adcc8a 100644
--- a/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/persistence/TaskDO.java
+++ b/powerjob-worker/src/main/java/com/github/kfcfans/powerjob/worker/persistence/TaskDO.java
@@ -68,6 +68,8 @@ public class TaskDO {
public String toString() {
return "{" +
"taskId='" + taskId + '\'' +
+ ", instanceId=" + instanceId +
+ ", subInstanceId=" + subInstanceId +
", taskName='" + taskName + '\'' +
", address='" + address + '\'' +
", status=" + status +
@@ -75,6 +77,7 @@ public class TaskDO {
", failedCnt=" + failedCnt +
", createdTime=" + createdTime +
", lastModifiedTime=" + lastModifiedTime +
+ ", lastReportTime=" + lastReportTime +
'}';
}
}
diff --git a/powerjob-worker/src/test/java/com/github/kfcfans/powerjob/ScriptProcessorTest.java b/powerjob-worker/src/test/java/com/github/kfcfans/powerjob/ScriptProcessorTest.java
index e4fbdba8..e7217255 100644
--- a/powerjob-worker/src/test/java/com/github/kfcfans/powerjob/ScriptProcessorTest.java
+++ b/powerjob-worker/src/test/java/com/github/kfcfans/powerjob/ScriptProcessorTest.java
@@ -1,9 +1,14 @@
package com.github.kfcfans.powerjob;
+import com.github.kfcfans.powerjob.worker.core.processor.TaskContext;
import com.github.kfcfans.powerjob.worker.core.processor.built.PythonProcessor;
import com.github.kfcfans.powerjob.worker.core.processor.built.ShellProcessor;
+import com.github.kfcfans.powerjob.worker.log.impl.OmsServerLogger;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import java.util.concurrent.ThreadLocalRandom;
+
/**
* 测试脚本处理器
*
@@ -14,25 +19,37 @@ public class ScriptProcessorTest {
private static final long timeout = 10000;
+ private static final TaskContext context = new TaskContext();
+
+ @BeforeAll
+ public static void initContext() {
+ context.setOmsLogger(new OmsServerLogger(1L));
+ }
+
@Test
public void testLocalShellProcessor() throws Exception {
ShellProcessor sp = new ShellProcessor(1L, "ls -a", timeout);
- sp.process(null);
+ System.out.println(sp.process(context));
ShellProcessor sp2 = new ShellProcessor(2777L, "pwd", timeout);
- sp2.process(null);
+ System.out.println(sp2.process(context));
}
@Test
public void testLocalPythonProcessor() throws Exception {
PythonProcessor pp = new PythonProcessor(2L, "print 'Hello World!'", timeout);
- pp.process(null);
+ System.out.println(pp.process(context));
}
@Test
public void testNetShellProcessor() throws Exception {
ShellProcessor sp = new ShellProcessor(18L, "http://localhost:8080/test/test.sh", timeout);
- sp.process(null);
+ System.out.println(sp.process(context));
}
+ @Test
+ public void testFailedScript() throws Exception {
+ ShellProcessor sp3 = new ShellProcessor(ThreadLocalRandom.current().nextLong(), "mvn tjq", timeout);
+ System.out.println(sp3.process(context));
+ }
}