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)); + } }